Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus...
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 7 Feb 2008 17:02:26 +0000 (09:02 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 7 Feb 2008 17:02:26 +0000 (09:02 -0800)
* 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (69 commits)
  [POWERPC] Add SPE registers to core dumps
  [POWERPC] Use regset code for compat PTRACE_*REGS* calls
  [POWERPC] Use generic compat_sys_ptrace
  [POWERPC] Use generic compat_ptrace_request
  [POWERPC] Use generic ptrace peekdata/pokedata
  [POWERPC] Use regset code for PTRACE_*REGS* requests
  [POWERPC] Switch to generic compat_binfmt_elf code
  [POWERPC] Switch to using user_regset-based core dumps
  [POWERPC] Add user_regset compat support
  [POWERPC] Add user_regset_view definitions
  [POWERPC] Use user_regset accessors for GPRs
  [POWERPC] ptrace accessors for special regs MSR and TRAP
  [POWERPC] Use user_regset accessors for SPE regs
  [POWERPC] Use user_regset accessors for altivec regs
  [POWERPC] Use user_regset accessors for FP regs
  [POWERPC] mpc52xx: fix compile error introduce when rebasing patch
  [POWERPC] 4xx: PCIe indirect DCR spinlock fix.
  [POWERPC] Add missing native dcr dcr_ind_lock spinlock
  [POWERPC] 4xx: Fix offset value on Warp board
  [POWERPC] 4xx: Add 440EPx Sequoia ehci dts entry
  ...

866 files changed:
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-kernel-uids
Documentation/BUG-HUNTING
Documentation/DocBook/genericirq.tmpl
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/kernel-locking.tmpl
Documentation/DocBook/lsm.tmpl
Documentation/DocBook/mtdnand.tmpl
Documentation/DocBook/procfs-guide.tmpl
Documentation/DocBook/rapidio.tmpl
Documentation/DocBook/videobook.tmpl
Documentation/DocBook/z8530book.tmpl
Documentation/cgroups.txt
Documentation/controllers/memory.txt [new file with mode: 0644]
Documentation/cpusets.txt
Documentation/dnotify.txt [deleted file]
Documentation/drivers/edac/edac.txt [deleted file]
Documentation/edac.txt [new file with mode: 0644]
Documentation/email-clients.txt
Documentation/fb/deferred_io.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/00-INDEX
Documentation/filesystems/Locking
Documentation/filesystems/dnotify.txt [new file with mode: 0644]
Documentation/filesystems/porting
Documentation/filesystems/proc.txt
Documentation/filesystems/sharedsubtree.txt [new file with mode: 0644]
Documentation/filesystems/vfs.txt
Documentation/kprobes.txt
Documentation/kref.txt
Documentation/md.txt
Documentation/rtc.txt
Documentation/sched-arch.txt [deleted file]
Documentation/sched-coding.txt [deleted file]
Documentation/sched-design-CFS.txt [deleted file]
Documentation/sched-design.txt [deleted file]
Documentation/sched-domains.txt [deleted file]
Documentation/sched-nice-design.txt [deleted file]
Documentation/sched-stats.txt [deleted file]
Documentation/scheduler/00-INDEX [new file with mode: 0644]
Documentation/scheduler/sched-arch.txt [new file with mode: 0644]
Documentation/scheduler/sched-coding.txt [new file with mode: 0644]
Documentation/scheduler/sched-design-CFS.txt [new file with mode: 0644]
Documentation/scheduler/sched-design.txt [new file with mode: 0644]
Documentation/scheduler/sched-domains.txt [new file with mode: 0644]
Documentation/scheduler/sched-nice-design.txt [new file with mode: 0644]
Documentation/scheduler/sched-stats.txt [new file with mode: 0644]
Documentation/sharedsubtree.txt [deleted file]
Documentation/sysctl/fs.txt
Documentation/sysctl/vm.txt
Documentation/unaligned-memory-access.txt [new file with mode: 0644]
Documentation/w1/masters/00-INDEX
Documentation/w1/masters/w1-gpio [new file with mode: 0644]
MAINTAINERS
REPORTING-BUGS
arch/alpha/Kconfig.debug
arch/alpha/defconfig
arch/alpha/kernel/core_irongate.c
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/smp.c
arch/alpha/mm/numa.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-rpc/riscpc.c
arch/arm/mm/init.c
arch/arm/mm/mmu.c
arch/arm/mm/nommu.c
arch/arm/plat-omap/fb.c
arch/avr32/kernel/setup.c
arch/avr32/lib/delay.c
arch/blackfin/kernel/setup.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf533/boards/H8606.c
arch/blackfin/mach-bf533/boards/cm_bf533.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/cm_bf537.c
arch/blackfin/mach-bf537/boards/generic_board.c
arch/blackfin/mach-bf537/boards/minotaur.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/cris/kernel/setup.c
arch/frv/kernel/setup.c
arch/h8300/kernel/irq.c
arch/h8300/kernel/setup.c
arch/ia64/kernel/machine_kexec.c
arch/ia64/kernel/smpboot.c
arch/ia64/mm/contig.c
arch/ia64/mm/discontig.c
arch/ia64/sn/pci/pcibr/pcibr_provider.c
arch/m32r/kernel/setup.c
arch/m32r/kernel/smpboot.c
arch/m32r/mm/discontig.c
arch/m68k/amiga/chipram.c
arch/m68k/amiga/cia.c
arch/m68k/atari/stram.c
arch/m68k/kernel/setup.c
arch/m68knommu/kernel/setup.c
arch/m68knommu/lib/memcpy.c
arch/mips/au1000/common/gpio.c
arch/mips/kernel/setup.c
arch/mips/kernel/smp.c
arch/mips/kernel/sysirix.c
arch/mips/sgi-ip27/ip27-memory.c
arch/parisc/Kconfig.debug
arch/parisc/configs/a500_defconfig
arch/parisc/mm/init.c
arch/powerpc/kernel/time.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/numa.c
arch/powerpc/platforms/powermac/cpufreq_32.c
arch/ppc/8260_io/enet.c
arch/ppc/8260_io/fcc_enet.c
arch/ppc/kernel/vmlinux.lds.S
arch/ppc/platforms/prep_setup.c
arch/s390/kernel/setup.c
arch/sh/boards/landisk/setup.c
arch/sh/boards/lboxre2/setup.c
arch/sh/boards/renesas/r7780rp/setup.c
arch/sh/boards/renesas/rts7751r2d/setup.c
arch/sh/boards/renesas/sdk7780/setup.c
arch/sh/boards/se/7722/setup.c
arch/sh/kernel/setup.c
arch/sh/mm/numa.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/systbls.S
arch/sparc/mm/init.c
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/iommu.c
arch/sparc64/kernel/iommu_common.c [deleted file]
arch/sparc64/kernel/iommu_common.h
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/mm/init.c
arch/sparc64/solaris/fs.c
arch/sparc64/solaris/timod.c
arch/v850/kernel/anna.c
arch/v850/kernel/as85ep1.c
arch/v850/kernel/rte_ma1_cb.c
arch/v850/kernel/setup.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/ia32/ia32_aout.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/cyrix.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/head_64.S
arch/x86/kernel/machine_kexec_32.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/mpparse_32.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/quirks.c
arch/x86/kernel/setup_32.c
arch/x86/kernel/setup_64.c
arch/x86/kernel/smpboot_32.c
arch/x86/kernel/test_nx.c
arch/x86/kernel/traps_32.c
arch/x86/lib/delay_32.c
arch/x86/lib/delay_64.c
arch/x86/mach-voyager/voyager_smp.c
arch/x86/mm/discontig_32.c
arch/x86/mm/fault.c
arch/x86/mm/init_64.c
arch/x86/mm/numa_64.c
arch/x86/mm/pageattr-test.c
arch/x86/mm/pageattr.c
arch/x86/mm/srat_64.c
arch/xtensa/kernel/time.c
crypto/async_tx/async_memcpy.c
crypto/async_tx/async_memset.c
crypto/async_tx/async_tx.c
crypto/async_tx/async_xor.c
crypto/cbc.c
crypto/cryptd.c
crypto/ecb.c
crypto/hmac.c
crypto/lrw.c
crypto/pcbc.c
crypto/xcbc.c
drivers/ata/ahci.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/pata_of_platform.c
drivers/ata/pata_platform.c
drivers/ata/sata_fsl.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_via.c
drivers/base/cpu.c
drivers/block/ataflop.c
drivers/block/cciss.c
drivers/block/loop.c
drivers/block/paride/pt.c
drivers/block/pktcdvd.c
drivers/block/rd.c
drivers/cdrom/cdrom.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/epca.h
drivers/char/esp.c
drivers/char/hvc_console.c
drivers/char/hvcs.c
drivers/char/hw_random/via-rng.c
drivers/char/i8k.c
drivers/char/ip2/ip2main.c
drivers/char/ip27-rtc.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/istallion.c
drivers/char/lp.c
drivers/char/mbcs.c
drivers/char/mbcs.h
drivers/char/mxser.c
drivers/char/mxser.h
drivers/char/mxser_new.c [deleted file]
drivers/char/mxser_new.h [deleted file]
drivers/char/n_tty.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/random.c
drivers/char/riscom8.c
drivers/char/riscom8.h
drivers/char/rocket.c
drivers/char/rocket_int.h
drivers/char/ser_a2232.c
drivers/char/serial167.c
drivers/char/specialix.c
drivers/char/specialix_io8.h
drivers/char/stallion.c
drivers/char/sx.h
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_infineon.c
drivers/char/tty_io.c
drivers/char/vt.c
drivers/dma/Kconfig
drivers/dma/dmaengine.c
drivers/dma/ioat_dma.c
drivers/dma/iop-adma.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/cell_edac.c [new file with mode: 0644]
drivers/edac/edac_core.h
drivers/edac/edac_device.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_pci.c
drivers/edac/edac_pci_sysfs.c
drivers/edac/i3000_edac.c
drivers/edac/mpc85xx_edac.c [new file with mode: 0644]
drivers/edac/mpc85xx_edac.h [new file with mode: 0644]
drivers/edac/mv64x60_edac.c [new file with mode: 0644]
drivers/edac/mv64x60_edac.h [new file with mode: 0644]
drivers/firmware/dcdbas.c
drivers/firmware/dmi-id.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/pca9539.c [deleted file]
drivers/gpio/pca953x.c [new file with mode: 0644]
drivers/ide/ide-probe.c
drivers/ide/legacy/ide_platform.c
drivers/input/touchscreen/h3600_ts_input.c
drivers/isdn/act2000/module.c
drivers/isdn/gigaset/asyncdata.c
drivers/isdn/gigaset/bas-gigaset.c
drivers/isdn/gigaset/common.c
drivers/isdn/gigaset/ev-layer.c
drivers/isdn/gigaset/gigaset.h
drivers/isdn/gigaset/interface.c
drivers/isdn/gigaset/isocdata.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/gigaset/usb-gigaset.c
drivers/isdn/hardware/eicon/debug.c
drivers/isdn/hardware/eicon/diva.c
drivers/isdn/hardware/eicon/message.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/i4l/isdn_ttyfax.c
drivers/isdn/icn/icn.c
drivers/isdn/isdnloop/isdnloop.c
drivers/md/bitmap.c
drivers/md/faulty.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/mktables.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid6test/test.c
drivers/media/video/Makefile
drivers/media/video/tvmixer.c [deleted file]
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/asic3.c [new file with mode: 0644]
drivers/misc/asus-laptop.c
drivers/misc/fujitsu-laptop.c
drivers/misc/lkdtm.c
drivers/misc/msi-laptop.c
drivers/misc/phantom.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/phram.c
drivers/mtd/maps/mtx-1_flash.c
drivers/net/forcedeth.c
drivers/net/gianfar_mii.c
drivers/net/iseries_veth.c
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/mv643xx_eth.c
drivers/net/pppol2tp.c
drivers/net/sky2.c
drivers/net/sky2.h
drivers/net/tlan.c
drivers/net/tulip/xircom_cb.c
drivers/net/ucc_geth_mii.c
drivers/net/virtio_net.c
drivers/net/wan/hdlc.c
drivers/net/wan/hdlc_cisco.c
drivers/net/wan/hdlc_fr.c
drivers/net/wan/hdlc_ppp.c
drivers/net/wan/hdlc_raw.c
drivers/net/wan/hdlc_raw_eth.c
drivers/net/wan/hdlc_x25.c
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/dma.h
drivers/net/wireless/b43legacy/dma.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/pio.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/b43legacy/xmit.h
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/parport/parport_pc.c
drivers/parport/parport_serial.c
drivers/pci/dmar.c
drivers/pci/intel-iommu.c
drivers/pci/intel-iommu.h
drivers/pci/iova.c
drivers/pci/iova.h
drivers/pnp/driver.c
drivers/pnp/interface.c
drivers/pnp/manager.c
drivers/pnp/pnpacpi/rsparser.c
drivers/pnp/pnpbios/core.c
drivers/pnp/pnpbios/rsparser.c
drivers/pnp/quirks.c
drivers/power/power_supply_sysfs.c
drivers/ps3/ps3av.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-at91sam9.c [new file with mode: 0644]
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1302.c [new file with mode: 0644]
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1511.c [new file with mode: 0644]
drivers/rtc/rtc-pcf8583.c
drivers/rtc/rtc-r9701.c [new file with mode: 0644]
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-sysfs.c
drivers/s390/sysinfo.c
drivers/scsi/a2091.c
drivers/scsi/a3000.c
drivers/scsi/aic7xxx_old.c
drivers/scsi/gvp11.c
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/scsi/megaraid/megaraid_sas.c
drivers/serial/68328serial.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/crisv10.c
drivers/serial/dz.c
drivers/serial/dz.h
drivers/serial/imx.c
drivers/serial/sc26xx.c [new file with mode: 0644]
drivers/serial/uartlite.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/atmel_spi.c
drivers/spi/omap2_mcspi.c
drivers/spi/pxa2xx_spi.c
drivers/spi/spi.c
drivers/spi/spi_bfin5xx.c
drivers/spi/spi_imx.c
drivers/spi/spi_s3c24xx.c
drivers/spi/spi_s3c24xx_gpio.c
drivers/spi/spi_sh_sci.c [new file with mode: 0644]
drivers/uio/uio.c
drivers/video/atmel_lcdfb.c
drivers/video/backlight/Kconfig
drivers/video/bf54x-lq043fb.c
drivers/video/console/bitblit.c
drivers/video/console/fbcon.c
drivers/video/console/fbcon.h
drivers/video/console/fbcon_ccw.c
drivers/video/console/fbcon_cw.c
drivers/video/console/fbcon_ud.c
drivers/video/console/fonts.c
drivers/video/console/tileblit.c
drivers/video/console/vgacon.c
drivers/video/fb_defio.c
drivers/video/fb_draw.h
drivers/video/fbmon.c
drivers/video/geode/lxfb_core.c
drivers/video/hpfb.c
drivers/video/i810/i810_main.c
drivers/video/igafb.c
drivers/video/intelfb/intelfbhw.c
drivers/video/neofb.c
drivers/video/nvidia/nvidia.c
drivers/video/pm2fb.c
drivers/video/pm3fb.c
drivers/video/pmag-aa-fb.c
drivers/video/ps3fb.c
drivers/video/s3c2410fb.c
drivers/video/s3c2410fb.h
drivers/video/sis/sis_main.c
drivers/video/sm501fb.c
drivers/video/tdfxfb.c
drivers/video/uvesafb.c
drivers/video/vermilion/vermilion.c
drivers/virtio/virtio_balloon.c
drivers/w1/masters/Kconfig
drivers/w1/masters/Makefile
drivers/w1/masters/ds1wm.c
drivers/w1/masters/w1-gpio.c [new file with mode: 0644]
drivers/w1/slaves/w1_therm.c
drivers/w1/w1.c
fs/9p/fid.c
fs/9p/v9fs.c
fs/9p/v9fs.h
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/Kconfig
fs/affs/affs.h
fs/affs/amigaffs.c
fs/affs/inode.c
fs/affs/namei.c
fs/affs/super.c
fs/afs/dir.c
fs/afs/inode.c
fs/afs/security.c
fs/autofs/autofs_i.h
fs/autofs/inode.c
fs/autofs/root.c
fs/bad_inode.c
fs/befs/linuxvfs.c
fs/bfs/bfs.h
fs/bfs/dir.c
fs/bfs/inode.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/block_dev.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/inode.c
fs/compat.c
fs/compat_ioctl.c
fs/dcache.c
fs/dquot.c
fs/ecryptfs/crypto.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/ecryptfs/keystore.c
fs/ecryptfs/main.c
fs/ecryptfs/mmap.c
fs/ecryptfs/read_write.c
fs/ecryptfs/super.c
fs/efs/inode.c
fs/efs/namei.c
fs/efs/super.c
fs/eventfd.c
fs/ext2/balloc.c
fs/ext2/dir.c
fs/ext2/ext2.h
fs/ext2/file.c
fs/ext2/inode.c
fs/ext2/ioctl.c
fs/ext2/namei.c
fs/ext2/super.c
fs/ext3/balloc.c
fs/ext3/ialloc.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext3/resize.c
fs/ext3/super.c
fs/ext4/balloc.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/resize.c
fs/ext4/super.c
fs/fat/file.c
fs/fat/inode.c
fs/fat/misc.c
fs/file.c
fs/freevxfs/vxfs_extern.h
fs/freevxfs/vxfs_inode.c
fs/freevxfs/vxfs_lookup.c
fs/freevxfs/vxfs_super.c
fs/fs-writeback.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/dir.c
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/ops_export.c
fs/gfs2/ops_inode.c
fs/hfs/bfind.c
fs/hfs/brec.c
fs/hfs/btree.c
fs/hfs/hfs.h
fs/hfs/super.c
fs/hfsplus/btree.c
fs/hfsplus/dir.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/super.c
fs/hostfs/hostfs_kern.c
fs/hppfs/hppfs_kern.c
fs/inode.c
fs/inotify.c
fs/inotify_user.c
fs/ioctl.c
fs/isofs/export.c
fs/isofs/inode.c
fs/isofs/namei.c
fs/isofs/rock.c
fs/jbd/journal.c
fs/jbd/recovery.c
fs/jbd2/recovery.c
fs/jffs2/dir.c
fs/jffs2/fs.c
fs/jffs2/os-linux.h
fs/jffs2/super.c
fs/jffs2/write.c
fs/jfs/inode.c
fs/jfs/jfs_inode.h
fs/jfs/namei.c
fs/jfs/super.c
fs/minix/inode.c
fs/minix/minix.h
fs/minix/namei.c
fs/namei.c
fs/namespace.c
fs/ncpfs/inode.c
fs/nfs/getroot.c
fs/nfsd/export.c
fs/openpromfs/inode.c
fs/partitions/Kconfig
fs/pnode.c
fs/proc/inode.c
fs/proc/proc_misc.c
fs/qnx4/inode.c
fs/qnx4/namei.c
fs/quota.c
fs/reiserfs/inode.c
fs/reiserfs/prints.c
fs/reiserfs/xattr.c
fs/romfs/inode.c
fs/select.c
fs/signalfd.c
fs/smbfs/sock.c
fs/sysv/inode.c
fs/sysv/namei.c
fs/sysv/super.c
fs/sysv/sysv.h
fs/ufs/inode.c
fs/ufs/namei.c
fs/ufs/super.c
fs/ufs/ufs.h
fs/utimes.c
fs/vfat/namei.c
include/asm-alpha/elf.h
include/asm-alpha/page.h
include/asm-alpha/system.h
include/asm-alpha/user.h
include/asm-arm/arch-iop13xx/adma.h
include/asm-arm/arch-s3c2410/regs-lcd.h
include/asm-arm/arch-s3c2410/spi-gpio.h
include/asm-arm/arch-s3c2410/spi.h
include/asm-arm/elf.h
include/asm-arm/hardware/iop3xx-adma.h
include/asm-arm/page.h
include/asm-arm/system.h
include/asm-arm/user.h
include/asm-avr32/delay.h
include/asm-avr32/elf.h
include/asm-avr32/page.h
include/asm-avr32/system.h
include/asm-avr32/timex.h
include/asm-avr32/user.h
include/asm-blackfin/elf.h
include/asm-blackfin/io.h
include/asm-blackfin/page.h
include/asm-blackfin/system.h
include/asm-blackfin/user.h
include/asm-cris/elf.h
include/asm-cris/page.h
include/asm-cris/system.h
include/asm-cris/user.h
include/asm-frv/Kbuild
include/asm-frv/elf.h
include/asm-frv/page.h
include/asm-frv/system.h
include/asm-generic/Kbuild.asm
include/asm-generic/cmpxchg-local.h [new file with mode: 0644]
include/asm-generic/cmpxchg.h [new file with mode: 0644]
include/asm-generic/cputime.h
include/asm-generic/sections.h
include/asm-h8300/elf.h
include/asm-h8300/io.h
include/asm-h8300/page.h
include/asm-h8300/system.h
include/asm-h8300/user.h
include/asm-h8300/virtconvert.h
include/asm-ia64/elf.h
include/asm-ia64/intrinsics.h
include/asm-ia64/page.h
include/asm-ia64/user.h
include/asm-m32r/delay.h
include/asm-m32r/elf.h
include/asm-m32r/local.h
include/asm-m32r/page.h
include/asm-m32r/system.h
include/asm-m32r/user.h
include/asm-m68k/elf.h
include/asm-m68k/page.h
include/asm-m68k/pgtable.h
include/asm-m68k/system.h
include/asm-m68k/user.h
include/asm-m68knommu/elf.h
include/asm-m68knommu/io.h
include/asm-m68knommu/page.h
include/asm-m68knommu/system.h
include/asm-mips/cmpxchg.h
include/asm-mips/elf.h
include/asm-mips/page.h
include/asm-mips/user.h
include/asm-parisc/atomic.h
include/asm-parisc/elf.h
include/asm-parisc/page.h
include/asm-powerpc/cputime.h
include/asm-powerpc/dma.h
include/asm-powerpc/paca.h
include/asm-powerpc/page.h
include/asm-powerpc/page_32.h
include/asm-powerpc/page_64.h
include/asm-powerpc/ps3av.h
include/asm-powerpc/system.h
include/asm-powerpc/user.h
include/asm-ppc/system.h
include/asm-s390/cputime.h
include/asm-s390/elf.h
include/asm-s390/kexec.h
include/asm-s390/page.h
include/asm-s390/system.h
include/asm-s390/user.h
include/asm-sh/delay.h
include/asm-sh/page.h
include/asm-sh/user.h
include/asm-sparc/atomic.h
include/asm-sparc/elf.h
include/asm-sparc/page.h
include/asm-sparc/system.h
include/asm-sparc/unistd.h
include/asm-sparc64/elf.h
include/asm-sparc64/io.h
include/asm-sparc64/page.h
include/asm-sparc64/system.h
include/asm-sparc64/timex.h
include/asm-sparc64/unistd.h
include/asm-v850/elf.h
include/asm-v850/io.h
include/asm-v850/page.h
include/asm-v850/system.h
include/asm-v850/user.h
include/asm-x86/Kbuild
include/asm-x86/cmpxchg_64.h
include/asm-x86/delay.h
include/asm-x86/elf.h
include/asm-x86/mmzone_32.h
include/asm-x86/pgalloc_64.h
include/asm-x86/termios.h
include/asm-x86/timex.h
include/asm-x86/user.h
include/asm-x86/user_32.h
include/asm-x86/user_64.h
include/asm-xtensa/elf.h
include/asm-xtensa/page.h
include/asm-xtensa/system.h
include/linux/Kbuild
include/linux/a.out.h
include/linux/ac97_codec.h
include/linux/acct.h
include/linux/async_tx.h
include/linux/ata_platform.h [new file with mode: 0644]
include/linux/bootmem.h
include/linux/cgroup.h
include/linux/cgroup_subsys.h
include/linux/compat.h
include/linux/cpuidle.h
include/linux/dmaengine.h
include/linux/ds1wm.h
include/linux/efs_fs.h
include/linux/elf.h
include/linux/elfcore.h
include/linux/err.h
include/linux/ext3_fs.h
include/linux/ext4_fs.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/hash.h
include/linux/hayesesp.h
include/linux/hdlc.h
include/linux/i2c/pca9539.h [deleted file]
include/linux/i2c/pca953x.h [new file with mode: 0644]
include/linux/if_vlan.h
include/linux/init.h
include/linux/interrupt.h
include/linux/isdn.h
include/linux/isicom.h
include/linux/istallion.h
include/linux/jbd.h
include/linux/kernel.h
include/linux/kexec.h
include/linux/kprobes.h
include/linux/libata.h
include/linux/log2.h
include/linux/loop.h
include/linux/lp.h
include/linux/memcontrol.h [new file with mode: 0644]
include/linux/mfd/asic3.h [new file with mode: 0644]
include/linux/mm_types.h
include/linux/pata_platform.h [deleted file]
include/linux/pci_ids.h
include/linux/percpu.h
include/linux/pkt_cls.h
include/linux/pnp.h
include/linux/ptrace.h
include/linux/qnx4_fs.h
include/linux/raid/bitmap.h
include/linux/raid/md_k.h
include/linux/rcupdate.h
include/linux/res_counter.h [new file with mode: 0644]
include/linux/rmap.h
include/linux/sched.h
include/linux/serial167.h
include/linux/shm.h
include/linux/signal.h
include/linux/sm501.h
include/linux/ssb/ssb.h
include/linux/stallion.h
include/linux/swap.h
include/linux/timex.h
include/linux/tty.h
include/linux/vt_kern.h
include/linux/w1-gpio.h [new file with mode: 0644]
include/net/9p/9p.h
include/net/9p/client.h
include/net/9p/conn.h [deleted file]
include/net/9p/transport.h
include/video/atmel_lcdc.h
init/Kconfig
init/calibrate.c
init/do_mounts.c
init/initramfs.c
init/main.c
ipc/msg.c
ipc/sem.c
ipc/shm.c
ipc/util.c
kernel/Makefile
kernel/cgroup.c
kernel/cpuset.c
kernel/exit.c
kernel/fork.c
kernel/kallsyms.c
kernel/kexec.c
kernel/kprobes.c
kernel/notifier.c
kernel/params.c
kernel/pid.c
kernel/printk.c
kernel/ptrace.c
kernel/relay.c
kernel/res_counter.c [new file with mode: 0644]
kernel/signal.c
kernel/srcu.c
kernel/stop_machine.c
kernel/sys.c
kernel/sysctl.c
kernel/test_kprobes.c
kernel/time.c
kernel/time/clocksource.c
kernel/timer.c
lib/extable.c
lib/smp_processor_id.c
mm/Makefile
mm/allocpercpu.c
mm/bootmem.c
mm/filemap.c
mm/memcontrol.c [new file with mode: 0644]
mm/memory.c
mm/migrate.c
mm/mmap.c
mm/oom_kill.c
mm/page_alloc.c
mm/rmap.c
mm/shmem.c
mm/swap.c
mm/swapfile.c
mm/vmscan.c
net/9p/Makefile
net/9p/client.c
net/9p/fcprint.c
net/9p/mod.c
net/9p/mux.c [deleted file]
net/9p/trans_fd.c
net/9p/trans_virtio.c
net/9p/util.c
net/ipv4/ipvs/ip_vs_wrr.c
net/mac80211/Kconfig
net/rxrpc/af_rxrpc.c
net/sched/cls_flow.c
net/sched/em_meta.c
scripts/checkstack.pl
scripts/kallsyms.c
scripts/kernel-doc
security/Kconfig
security/keys/key.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/security.c
security/selinux/include/security.h
security/selinux/ss/services.c
sound/oss/Makefile
sound/oss/ac97_codec.c
sound/oss/btaudio.c [deleted file]
sound/oss/cs4232.c [deleted file]
sound/oss/dmasound/Kconfig
sound/oss/dmasound/dmasound_paula.c
sound/oss/i810_audio.c [deleted file]
sound/oss/pss.c
sound/oss/sb_common.c
sound/oss/trident.c
sound/oss/via82cxxx_audio.c [deleted file]

index 40ac7759c3bb5342edf9168153edbf1f1ff05e79..d273b557a9340a6f32f7171c5138081f1ae9e177 100644 (file)
@@ -126,18 +126,16 @@ devices.txt
        - plain ASCII listing of all the nodes in /dev/ with major minor #'s.
 digiepca.txt
        - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
-dnotify.txt
-       - info about directory notification in Linux.
 dontdiff
        - file containing a list of files that should never be diff'ed.
 driver-model/
        - directory with info about Linux driver model.
-drivers/
-       - directory with driver documentation (currently only EDAC).
 dvb/
        - info on Linux Digital Video Broadcast (DVB) subsystem.
 early-userspace/
        - info about initramfs, klibc, and userspace early during boot.
+edac.txt
+       - information on EDAC - Error Detection And Correction
 eisa.txt
        - info on EISA bus support.
 exception.txt
@@ -334,20 +332,8 @@ rtc.txt
        - notes on how to use the Real Time Clock (aka CMOS clock) driver.
 s390/
        - directory with info on using Linux on the IBM S390.
-sched-arch.txt
-       - CPU Scheduler implementation hints for architecture specific code.
-sched-coding.txt
-       - reference for various scheduler-related methods in the O(1) scheduler.
-sched-design.txt
-       - goals, design and implementation of the Linux O(1) scheduler.
-sched-design-CFS.txt
-       - goals, design and implementation of the Complete Fair Scheduler.
-sched-domains.txt
-       - information on scheduling domains.
-sched-nice-design.txt
-       - How and why the scheduler's nice levels are implemented.
-sched-stats.txt
-       - information on schedstats (Linux Scheduler Statistics).
+scheduler/
+       - directory with info on the scheduler.
 scsi/
        - directory with info on Linux scsi support.
 serial/
@@ -360,8 +346,6 @@ sgi-visws.txt
        - short blurb on the SGI Visual Workstations.
 sh/
        - directory with info on porting Linux to a new architecture.
-sharedsubtree.txt
-       - a description of shared subtrees for namespaces.
 smart-config.txt
        - description of the Smart Config makefile feature.
 sony-laptop.txt
index 648d65dbc0e736b06e57b77551e13dcfd3d1499f..28f14695a8523594ebcc806ae0a12832b032a851 100644 (file)
@@ -11,4 +11,4 @@ Description:
                example would be, if User A has shares = 1024 and user
                B has shares = 2048, User B will get twice the CPU
                bandwidth user A will. For more details refer
-               Documentation/sched-design-CFS.txt
+               Documentation/scheduler/sched-design-CFS.txt
index 6c816751b8686394d8cbdbd1fc639154d7f5b7ac..65022a87bf17902f9e04fe5ecff611a41ffaf4d8 100644 (file)
@@ -214,6 +214,23 @@ And recompile the kernel with CONFIG_DEBUG_INFO enabled:
   gdb vmlinux
   (gdb) p vt_ioctl
   (gdb) l *(0x<address of vt_ioctl> + 0xda8)
+or, as one command
+  (gdb) l *(vt_ioctl + 0xda8)
+
+If you have a call trace, such as :-
+>Call Trace:
+> [<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5
+> [<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e
+> [<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee
+> ...
+this shows the problem in the :jbd: module. You can load that module in gdb
+and list the relevant code.
+  gdb fs/jbd/jbd.ko
+  (gdb) p log_wait_commit
+  (gdb) l *(0x<address> + 0xa3)
+or
+  (gdb) l *(log_wait_commit + 0xa3)
+
 
 Another very useful option of the Kernel Hacking section in menuconfig is
 Debug memory allocations. This will help you see whether data has been
index 4215f69ce7e6368331d59d5d17d17059cb4e97ca..3a882d9a90a9134317799a2b0357b53e3dcdb8fd 100644 (file)
          <listitem><para>Chiplevel hardware encapsulation</para></listitem>
        </orderedlist>
     </para>
-    <sect1>
+    <sect1 id="Interrupt_control_flow">
        <title>Interrupt control flow</title>
        <para>
        Each interrupt is described by an interrupt descriptor structure
        referenced by the assigned chip descriptor structure.
        </para>
     </sect1>
-    <sect1>
+    <sect1 id="Highlevel_Driver_API">
        <title>Highlevel Driver API</title>
        <para>
          The highlevel Driver API consists of following functions:
          See the autogenerated function documentation for details.
        </para>
     </sect1>
-    <sect1>
+    <sect1 id="Highlevel_IRQ_flow_handlers">
        <title>Highlevel IRQ flow handlers</title>
        <para>
          The generic layer provides a set of pre-defined irq-flow methods:
          specific) are assigned to specific interrupts by the architecture
          either during bootup or during device initialization.
        </para>
-       <sect2>
+       <sect2 id="Default_flow_implementations">
        <title>Default flow implementations</title>
-           <sect3>
+           <sect3 id="Helper_functions">
                <title>Helper functions</title>
                <para>
                The helper functions call the chip primitives and
@@ -267,9 +267,9 @@ noop(irq)
                </para>
            </sect3>
        </sect2>
-       <sect2>
+       <sect2 id="Default_flow_handler_implementations">
        <title>Default flow handler implementations</title>
-           <sect3>
+           <sect3 id="Default_Level_IRQ_flow_handler">
                <title>Default Level IRQ flow handler</title>
                <para>
                handle_level_irq provides a generic implementation
@@ -284,7 +284,7 @@ desc->chip->end();
                </programlisting>
                </para>
            </sect3>
-           <sect3>
+           <sect3 id="Default_Edge_IRQ_flow_handler">
                <title>Default Edge IRQ flow handler</title>
                <para>
                handle_edge_irq provides a generic implementation
@@ -311,7 +311,7 @@ desc->chip->end();
                </programlisting>
                </para>
            </sect3>
-           <sect3>
+           <sect3 id="Default_simple_IRQ_flow_handler">
                <title>Default simple IRQ flow handler</title>
                <para>
                handle_simple_irq provides a generic implementation
@@ -328,7 +328,7 @@ handle_IRQ_event(desc->action);
                </programlisting>
                </para>
            </sect3>
-           <sect3>
+           <sect3 id="Default_per_CPU_flow_handler">
                <title>Default per CPU flow handler</title>
                <para>
                handle_percpu_irq provides a generic implementation
@@ -349,7 +349,7 @@ desc->chip->end();
                </para>
            </sect3>
        </sect2>
-       <sect2>
+       <sect2 id="Quirks_and_optimizations">
        <title>Quirks and optimizations</title>
        <para>
        The generic functions are intended for 'clean' architectures and chips,
@@ -358,7 +358,7 @@ desc->chip->end();
        overriding the highlevel irq-flow handler.
        </para>
        </sect2>
-       <sect2>
+       <sect2 id="Delayed_interrupt_disable">
        <title>Delayed interrupt disable</title>
        <para>
        This per interrupt selectable feature, which was introduced by Russell
@@ -380,7 +380,7 @@ desc->chip->end();
        </para>
        </sect2>
     </sect1>
-    <sect1>
+    <sect1 id="Chiplevel_hardware_encapsulation">
        <title>Chiplevel hardware encapsulation</title>
        <para>
        The chip level hardware descriptor structure irq_chip
index 77436d735013f37195750aec890f7db57a1b130d..059aaf20951a3bb54a4604084b2b33d70d306af2 100644 (file)
@@ -165,6 +165,7 @@ X!Ilib/string.c
 !Emm/vmalloc.c
 !Imm/page_alloc.c
 !Emm/mempool.c
+!Emm/dmapool.c
 !Emm/page-writeback.c
 !Emm/truncate.c
      </sect1>
@@ -371,7 +372,6 @@ X!Iinclude/linux/device.h
 !Edrivers/base/class.c
 !Edrivers/base/firmware_class.c
 !Edrivers/base/transport_class.c
-!Edrivers/base/dmapool.c
 <!-- Cannot be included, because
      attribute_container_add_class_device_adapter
  and attribute_container_classdev_to_container
index 01825ee7db64031878c6c9e647cd698547c9d558..2e9d6b41f034594b3b1af87c97ab1da81f5caccd 100644 (file)
@@ -717,7 +717,7 @@ used, and when it gets full, throws out the least used one.
     <para>
 For our first example, we assume that all operations are in user
 context (ie. from system calls), so we can sleep.  This means we can
-use a semaphore to protect the cache and all the objects within
+use a mutex to protect the cache and all the objects within
 it.  Here's the code:
     </para>
 
@@ -725,7 +725,7 @@ it.  Here's the code:
 #include &lt;linux/list.h&gt;
 #include &lt;linux/slab.h&gt;
 #include &lt;linux/string.h&gt;
-#include &lt;asm/semaphore.h&gt;
+#include &lt;linux/mutex.h&gt;
 #include &lt;asm/errno.h&gt;
 
 struct object
@@ -737,7 +737,7 @@ struct object
 };
 
 /* Protects the cache, cache_num, and the objects within it */
-static DECLARE_MUTEX(cache_lock);
+static DEFINE_MUTEX(cache_lock);
 static LIST_HEAD(cache);
 static unsigned int cache_num = 0;
 #define MAX_CACHE_SIZE 10
@@ -789,17 +789,17 @@ int cache_add(int id, const char *name)
         obj-&gt;id = id;
         obj-&gt;popularity = 0;
 
-        down(&amp;cache_lock);
+        mutex_lock(&amp;cache_lock);
         __cache_add(obj);
-        up(&amp;cache_lock);
+        mutex_unlock(&amp;cache_lock);
         return 0;
 }
 
 void cache_delete(int id)
 {
-        down(&amp;cache_lock);
+        mutex_lock(&amp;cache_lock);
         __cache_delete(__cache_find(id));
-        up(&amp;cache_lock);
+        mutex_unlock(&amp;cache_lock);
 }
 
 int cache_find(int id, char *name)
@@ -807,13 +807,13 @@ int cache_find(int id, char *name)
         struct object *obj;
         int ret = -ENOENT;
 
-        down(&amp;cache_lock);
+        mutex_lock(&amp;cache_lock);
         obj = __cache_find(id);
         if (obj) {
                 ret = 0;
                 strcpy(name, obj-&gt;name);
         }
-        up(&amp;cache_lock);
+        mutex_unlock(&amp;cache_lock);
         return ret;
 }
 </programlisting>
@@ -853,7 +853,7 @@ The change is shown below, in standard patch format: the
          int popularity;
  };
 
--static DECLARE_MUTEX(cache_lock);
+-static DEFINE_MUTEX(cache_lock);
 +static spinlock_t cache_lock = SPIN_LOCK_UNLOCKED;
  static LIST_HEAD(cache);
  static unsigned int cache_num = 0;
@@ -870,22 +870,22 @@ The change is shown below, in standard patch format: the
          obj-&gt;id = id;
          obj-&gt;popularity = 0;
 
--        down(&amp;cache_lock);
+-        mutex_lock(&amp;cache_lock);
 +        spin_lock_irqsave(&amp;cache_lock, flags);
          __cache_add(obj);
--        up(&amp;cache_lock);
+-        mutex_unlock(&amp;cache_lock);
 +        spin_unlock_irqrestore(&amp;cache_lock, flags);
          return 0;
  }
 
  void cache_delete(int id)
  {
--        down(&amp;cache_lock);
+-        mutex_lock(&amp;cache_lock);
 +        unsigned long flags;
 +
 +        spin_lock_irqsave(&amp;cache_lock, flags);
          __cache_delete(__cache_find(id));
--        up(&amp;cache_lock);
+-        mutex_unlock(&amp;cache_lock);
 +        spin_unlock_irqrestore(&amp;cache_lock, flags);
  }
 
@@ -895,14 +895,14 @@ The change is shown below, in standard patch format: the
          int ret = -ENOENT;
 +        unsigned long flags;
 
--        down(&amp;cache_lock);
+-        mutex_lock(&amp;cache_lock);
 +        spin_lock_irqsave(&amp;cache_lock, flags);
          obj = __cache_find(id);
          if (obj) {
                  ret = 0;
                  strcpy(name, obj-&gt;name);
          }
--        up(&amp;cache_lock);
+-        mutex_unlock(&amp;cache_lock);
 +        spin_unlock_irqrestore(&amp;cache_lock, flags);
          return ret;
  }
index f63822195871bed47e6bd7c29076587cec361510..fe7664ce96678077eb2e461c10d1ebbe4dc9e42e 100644 (file)
@@ -33,7 +33,7 @@
  </authorgroup>
  </articleinfo>
 
-<sect1><title>Introduction</title>
+<sect1 id="Introduction"><title>Introduction</title>
 
 <para>
 In March 2001, the National Security Agency (NSA) gave a presentation
index 957cf5c26831a31df5b8adca8ecc3eb2feabad67..8e145857fc9dad52ff39f90dcac17015b4851fd0 100644 (file)
@@ -80,7 +80,7 @@
      struct member has a short description which is marked with an [XXX] identifier.
      The following chapters explain the meaning of those identifiers.
      </para>
-     <sect1>   
+     <sect1 id="Function_identifiers_XXX">
        <title>Function identifiers [XXX]</title>
        <para>
        The functions are marked with [XXX] identifiers in the short
                </para></listitem>
        </itemizedlist>
      </sect1>
-     <sect1>   
+     <sect1 id="Struct_member_identifiers_XXX">
        <title>Struct member identifiers [XXX]</title>
        <para>
        The struct members are marked with [XXX] identifiers in the 
                basic functions and fill out some really board dependent
                members in the nand chip description structure.
        </para>
-       <sect1>
+       <sect1 id="Basic_defines">
                <title>Basic defines</title>
                <para>
                        At least you have to provide a mtd structure and
@@ -185,7 +185,7 @@ static struct nand_chip board_chip;
 static unsigned long baseaddr;
                </programlisting>
        </sect1>
-       <sect1>
+       <sect1 id="Partition_defines">
                <title>Partition defines</title>
                <para>
                        If you want to divide your device into partitions, then
@@ -204,7 +204,7 @@ static struct mtd_partition partition_info[] = {
 };
                </programlisting>
        </sect1>
-       <sect1>
+       <sect1 id="Hardware_control_functions">
                <title>Hardware control function</title>
                <para>
                        The hardware control function provides access to the 
@@ -246,7 +246,7 @@ static void board_hwcontrol(struct mtd_info *mtd, int cmd)
 }
                </programlisting>
        </sect1>
-       <sect1>
+       <sect1 id="Device_ready_function">
                <title>Device ready function</title>
                <para>
                        If the hardware interface has the ready busy pin of the NAND chip connected to a
@@ -257,7 +257,7 @@ static void board_hwcontrol(struct mtd_info *mtd, int cmd)
                        the function must not be defined and the function pointer this->dev_ready is set to NULL.               
                </para>
        </sect1>
-       <sect1>
+       <sect1 id="Init_function">
                <title>Init function</title>
                <para>
                        The init function allocates memory and sets up all the board
@@ -325,7 +325,7 @@ out:
 module_init(board_init);
                </programlisting>
        </sect1>
-       <sect1>
+       <sect1 id="Exit_function">
                <title>Exit function</title>
                <para>
                        The exit function is only neccecary if the driver is
@@ -359,7 +359,7 @@ module_exit(board_cleanup);
                driver. For a list of functions which can be overridden by the board
                driver see the documentation of the nand_chip structure.
        </para>
-       <sect1>
+       <sect1 id="Multiple_chip_control">
                <title>Multiple chip control</title>
                <para>
                        The nand driver can control chip arrays. Therefor the
@@ -419,9 +419,9 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
 }
                </programlisting>
        </sect1>
-       <sect1>
+       <sect1 id="Hardware_ECC_support">
                <title>Hardware ECC support</title>
-               <sect2>
+               <sect2 id="Functions_and_constants">
                        <title>Functions and constants</title>
                        <para>
                                The nand driver supports three different types of
@@ -475,7 +475,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
                                </itemizedlist>
                        </para>
                </sect2>
-               <sect2>
+               <sect2 id="Hardware_ECC_with_syndrome_calculation">
                <title>Hardware ECC with syndrome calculation</title>
                        <para>
                                Many hardware ECC implementations provide Reed-Solomon
@@ -500,7 +500,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
                        </para>
                </sect2>
        </sect1>
-       <sect1>
+       <sect1 id="Bad_Block_table_support">
                <title>Bad block table support</title>
                <para>
                        Most NAND chips mark the bad blocks at a defined
@@ -552,7 +552,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
                        allows faster access than always checking the
                        bad block information on the flash chip itself.
                </para>
-               <sect2>
+               <sect2 id="Flash_based_tables">
                        <title>Flash based tables</title>
                        <para>
                                It may be desired or neccecary to keep a bad block table in FLASH. 
@@ -587,7 +587,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
                                </itemizedlist>
                        </para>
                </sect2>
-               <sect2>
+               <sect2 id="User_defined_tables">
                        <title>User defined tables</title>
                        <para>
                                User defined tables are created by filling out a 
@@ -676,7 +676,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
                        </para>
                </sect2>
        </sect1>
-       <sect1>
+       <sect1 id="Spare_area_placement">
                <title>Spare area (auto)placement</title>
                <para>
                        The nand driver implements different possibilities for
@@ -730,7 +730,7 @@ struct nand_oobinfo {
                        </para></listitem>
                        </itemizedlist>
                </para>
-               <sect2>
+               <sect2 id="Placement_defined_by_fs_driver">
                        <title>Placement defined by fs driver</title>
                        <para>
                                The calling function provides a pointer to a nand_oobinfo
@@ -760,7 +760,7 @@ struct nand_oobinfo {
                                done according to the given scheme in the nand_oobinfo structure.
                        </para>
                </sect2>
-               <sect2>
+               <sect2 id="Automatic_placement">
                        <title>Automatic placement</title>
                        <para>
                                Automatic placement uses the built in defaults to place the
@@ -774,7 +774,7 @@ struct nand_oobinfo {
                                done according to the default builtin scheme.
                        </para>
                </sect2>
-               <sect2>
+               <sect2 id="User_space_placement_selection">
                        <title>User space placement selection</title>
                <para>
                        All non ecc functions like mtd->read and mtd->write use an internal 
@@ -789,9 +789,9 @@ struct nand_oobinfo {
                </para>
                </sect2>
        </sect1>        
-       <sect1>
+       <sect1 id="Spare_area_autoplacement_default">
                <title>Spare area autoplacement default schemes</title>
-               <sect2>
+               <sect2 id="pagesize_256">
                        <title>256 byte pagesize</title>
 <informaltable><tgroup cols="3"><tbody>
 <row>
@@ -843,7 +843,7 @@ pages this byte is reserved</entry>
 </row>
 </tbody></tgroup></informaltable>
                </sect2>
-               <sect2>
+               <sect2 id="pagesize_512">
                        <title>512 byte pagesize</title>
 <informaltable><tgroup cols="3"><tbody>
 <row>
@@ -906,7 +906,7 @@ in this page</entry>
 </row>
 </tbody></tgroup></informaltable>
                </sect2>
-               <sect2>
+               <sect2 id="pagesize_2048">
                        <title>2048 byte pagesize</title>
 <informaltable><tgroup cols="3"><tbody>
 <row>
@@ -1126,9 +1126,9 @@ in this page</entry>
      <para>
      This chapter describes the constants which might be relevant for a driver developer.
      </para>
-     <sect1>   
+     <sect1 id="Chip_option_constants">
        <title>Chip option constants</title>
-       <sect2>   
+       <sect2 id="Constants_for_chip_id_table">
                <title>Constants for chip id table</title>
                <para>
                These constants are defined in nand.h. They are ored together to describe
@@ -1153,7 +1153,7 @@ in this page</entry>
                </programlisting>
                </para>
        </sect2>
-       <sect2>   
+       <sect2 id="Constants_for_runtime_options">
                <title>Constants for runtime options</title>
                <para>
                These constants are defined in nand.h. They are ored together to describe
@@ -1171,7 +1171,7 @@ in this page</entry>
        </sect2>
      </sect1>  
 
-     <sect1>   
+     <sect1 id="EEC_selection_constants">
        <title>ECC selection constants</title>
        <para>
        Use these constants to select the ECC algorithm.
@@ -1192,7 +1192,7 @@ in this page</entry>
        </para>
      </sect1>  
 
-     <sect1>   
+     <sect1 id="Hardware_control_related_constants">
        <title>Hardware control related constants</title>
        <para>
        These constants describe the requested hardware access function when
@@ -1218,7 +1218,7 @@ in this page</entry>
        </para>
      </sect1>  
 
-     <sect1>   
+     <sect1 id="Bad_block_table_constants">
        <title>Bad block table related constants</title>
        <para>
        These constants describe the options used for bad block
index 2de84dc195a8b46e52735a60bb9ce4097d4f7d67..1fd6a1ec7591d5f4179cdf2a641f1b055c1f486a 100644 (file)
@@ -85,7 +85,7 @@
 
 
 
-  <preface>
+  <preface id="Preface">
     <title>Preface</title>
 
     <para>
 
 
 
-    <sect1>
+    <sect1 id="Creating_a_symlink">
       <title>Creating a symlink</title>
 
       <funcsynopsis>
       </para>
     </sect1>
 
-    <sect1>
+    <sect1 id="Creating_a_directory">
       <title>Creating a directory</title>
       
       <funcsynopsis>
 
 
 
-    <sect1>
+    <sect1 id="Removing_an_entry">
       <title>Removing an entry</title>
       
       <funcsynopsis>
@@ -340,7 +340,7 @@ entry->write_proc = write_proc_foo;
 
 
 
-    <sect1>
+    <sect1 id="Reading_data">
       <title>Reading data</title>
 
       <para>
@@ -448,7 +448,7 @@ entry->write_proc = write_proc_foo;
 
 
 
-    <sect1>
+    <sect1 id="Writing_data">
       <title>Writing data</title>
 
       <para>
@@ -579,7 +579,7 @@ int foo_read_func(char *page, char **start, off_t off,
 
 
 
-    <sect1>
+    <sect1 id="Modules">
       <title>Modules</title>
 
       <para>
@@ -599,7 +599,7 @@ entry->owner = THIS_MODULE;
 
 
 
-    <sect1>
+    <sect1 id="Mode_and_ownership">
       <title>Mode and ownership</title>
 
       <para>
index a8b88c47e80951e0a93b61d831bd9a198fe5f07f..b9e143e28c641ebec67d7e422b8ff81e97cda2a4 100644 (file)
   <chapter id="bugs">
      <title>Known Bugs and Limitations</title>
 
-     <sect1>
+     <sect1 id="known_bugs">
        <title>Bugs</title>
          <para>None. ;)</para>
      </sect1>
-     <sect1>
+     <sect1 id="Limitations">
        <title>Limitations</title>
          <para>
            <orderedlist>
                on devices, request/map memory region resources,
                and manage mailboxes/doorbells.
        </para>
-       <sect1>
+       <sect1 id="Functions">
                <title>Functions</title>
 !Iinclude/linux/rio_drv.h
 !Edrivers/rapidio/rio-driver.c
      subsystem.
      </para>
 
-     <sect1><title>Structures</title>
+     <sect1 id="Structures"><title>Structures</title>
 !Iinclude/linux/rio.h
      </sect1>
-     <sect1><title>Enumeration and Discovery</title>
+     <sect1 id="Enumeration_and_Discovery"><title>Enumeration and Discovery</title>
 !Idrivers/rapidio/rio-scan.c
      </sect1>
-     <sect1><title>Driver functionality</title>
+     <sect1 id="Driver_functionality"><title>Driver functionality</title>
 !Idrivers/rapidio/rio.c
 !Idrivers/rapidio/rio-access.c
      </sect1>
-     <sect1><title>Device model support</title>
+     <sect1 id="Device_model_support"><title>Device model support</title>
 !Idrivers/rapidio/rio-driver.c
      </sect1>
-     <sect1><title>Sysfs support</title>
+     <sect1 id="Sysfs_support"><title>Sysfs support</title>
 !Idrivers/rapidio/rio-sysfs.c
      </sect1>
-     <sect1><title>PPC32 support</title>
+     <sect1 id="PPC32_support"><title>PPC32 support</title>
 !Iarch/powerpc/kernel/rio.c
 !Earch/powerpc/sysdev/fsl_rio.c
 !Iarch/powerpc/sysdev/fsl_rio.c
index b3d93ee27693057e5ab5555049a0d9500e92b634..89817795e668d438d3ea64f9dd37cfa9d0e55785 100644 (file)
@@ -170,7 +170,7 @@ int __init myradio_init(struct video_init *v)
   <para>
         The types available are
   </para>
-   <table frame="all"><title>Device Types</title>
+   <table frame="all" id="Device_Types"><title>Device Types</title>
    <tgroup cols="3" align="left">
    <tbody>
    <row>
@@ -291,7 +291,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
         allows the applications to find out what sort of a card they have found and
         to figure out what they want to do about it. The fields in the structure are
   </para>
-   <table frame="all"><title>struct video_capability fields</title>
+   <table frame="all" id="video_capability_fields"><title>struct video_capability fields</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -365,7 +365,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
   <para>
         The video_tuner structure has the following fields
   </para>
-   <table frame="all"><title>struct video_tuner fields</title>
+   <table frame="all" id="video_tuner_fields"><title>struct video_tuner fields</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -398,7 +398,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
     </tgroup>
     </table>
 
-   <table frame="all"><title>struct video_tuner flags</title>
+   <table frame="all" id="video_tuner_flags"><title>struct video_tuner flags</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -421,7 +421,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
     </tgroup>
     </table>
 
-   <table frame="all"><title>struct video_tuner modes</title>
+   <table frame="all" id="video_tuner_modes"><title>struct video_tuner modes</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -572,7 +572,7 @@ static int current_volume=0;
   <para>
         Then we fill in the video_audio structure. This has the following format
   </para>
-   <table frame="all"><title>struct video_audio fields</title>
+   <table frame="all" id="video_audio_fields"><title>struct video_audio fields</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -607,7 +607,7 @@ static int current_volume=0;
    </tgroup>
    </table>
 
-   <table frame="all"><title>struct video_audio flags</title>
+   <table frame="all" id="video_audio_flags"><title>struct video_audio flags</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -625,7 +625,7 @@ static int current_volume=0;
    </tgroup>
    </table>
 
-   <table frame="all"><title>struct video_audio modes</title>
+   <table frame="all" id="video_audio_modes"><title>struct video_audio modes</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -775,7 +775,7 @@ module_exit(cleanup);
   </para>
   </sect1>
   </chapter>
-  <chapter>
+  <chapter id="Video_Capture_Devices">
         <title>Video Capture Devices</title>
   <sect1 id="introvid">
   <title>Video Capture Device Types</title>
@@ -855,7 +855,7 @@ static struct video_device my_camera
         We use the extra video capability flags that did not apply to the
         radio interface. The video related flags are
   </para>
-   <table frame="all"><title>Capture Capabilities</title>
+   <table frame="all" id="Capture_Capabilities"><title>Capture Capabilities</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -1195,7 +1195,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
         inputs to the video card). Our example card has a single camera input. The
         fields in the structure are
   </para>
-   <table frame="all"><title>struct video_channel fields</title>
+   <table frame="all" id="video_channel_fields"><title>struct video_channel fields</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -1218,7 +1218,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
     </tbody>
     </tgroup>
     </table>
-    <table frame="all"><title>struct video_channel flags</title>
+    <table frame="all" id="video_channel_flags"><title>struct video_channel flags</title>
     <tgroup cols="2" align="left">
     <tbody>
     <row>
@@ -1229,7 +1229,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
     </tbody>
     </tgroup>
     </table>
-    <table frame="all"><title>struct video_channel types</title>
+    <table frame="all" id="video_channel_types"><title>struct video_channel types</title>
     <tgroup cols="2" align="left">
     <tbody>
     <row>
@@ -1242,7 +1242,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
     </tbody>
     </tgroup>
     </table>
-    <table frame="all"><title>struct video_channel norms</title>
+    <table frame="all" id="video_channel_norms"><title>struct video_channel norms</title>
     <tgroup cols="2" align="left">
     <tbody>
     <row>
@@ -1328,7 +1328,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
         for every other pixel in the image. The other common formats the interface 
         defines are
   </para>
-   <table frame="all"><title>Framebuffer Encodings</title>
+   <table frame="all" id="Framebuffer_Encodings"><title>Framebuffer Encodings</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -1466,7 +1466,7 @@ static struct video_buffer capture_fb;
         display. The video_window structure is used to describe the way the image 
         should be displayed. 
    </para>
-   <table frame="all"><title>struct video_window fields</title>
+   <table frame="all" id="video_window_fields"><title>struct video_window fields</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
@@ -1503,7 +1503,7 @@ static struct video_buffer capture_fb;
     <para>
         Each clip is a struct video_clip which has the following fields
    </para>
-   <table frame="all"><title>video_clip fields</title>
+   <table frame="all" id="video_clip_fields"><title>video_clip fields</title>
    <tgroup cols="2" align="left">
    <tbody>
    <row>
index a507876447aa387f916915f4febcfe4fbfc11035..42c75ba71ba220fed7976b30d9d601a806cf2ae6 100644 (file)
@@ -77,7 +77,7 @@
   </para>
   </chapter>
   
-  <chapter>
+  <chapter id="Driver_Modes">
        <title>Driver Modes</title>
   <para>
        The Z85230 driver layer can drive Z8530, Z85C30 and Z85230 devices
   </para>
   </chapter>
 
-  <chapter>
+  <chapter id="Using_the_Z85230_driver">
        <title>Using the Z85230 driver</title>
   <para>
        The Z85230 driver provides the back end interface to your board. To
   </para>
   </chapter>
 
-  <chapter>
+  <chapter id="Attaching_Network_Interfaces">
        <title>Attaching Network Interfaces</title>
   <para>
        If you wish to use the network interface facilities of the driver,
   </para>
   </chapter>
 
-  <chapter>
+  <chapter id="Configuring_And_Activating_The_Port">
        <title>Configuring And Activating The Port</title>
   <para>
        The Z85230 driver provides helper functions and tables to load the
   </para>
   </chapter>
 
-  <chapter>
+  <chapter id="Network_Layer_Functions">
        <title>Network Layer Functions</title>
   <para>
        The Z8530 layer provides functions to queue packets for
   </para>
   </chapter>
 
-  <chapter>
+  <chapter id="Porting_The_Z8530_Driver">
      <title>Porting The Z8530 Driver</title>
   <para>
        The Z8530 driver is written to be portable. In DMA mode it makes
index 98a26f81fa75062b104edb796f3b9a0449f6f28c..42d7c4cb39cdb7374ef5918236bbc711c71aad07 100644 (file)
@@ -456,7 +456,7 @@ methods are create/destroy. Any others that are null are presumed to
 be successful no-ops.
 
 struct cgroup_subsys_state *create(struct cgroup *cont)
-LL=cgroup_mutex
+(cgroup_mutex held by caller)
 
 Called to create a subsystem state object for a cgroup. The
 subsystem should allocate its subsystem state object for the passed
@@ -471,14 +471,19 @@ it's the root of the hierarchy) and may be an appropriate place for
 initialization code.
 
 void destroy(struct cgroup *cont)
-LL=cgroup_mutex
+(cgroup_mutex held by caller)
 
-The cgroup system is about to destroy the passed cgroup; the
-subsystem should do any necessary cleanup
+The cgroup system is about to destroy the passed cgroup; the subsystem
+should do any necessary cleanup and free its subsystem state
+object. By the time this method is called, the cgroup has already been
+unlinked from the file system and from the child list of its parent;
+cgroup->parent is still valid. (Note - can also be called for a
+newly-created cgroup if an error occurs after this subsystem's
+create() method has been called for the new cgroup).
 
 int can_attach(struct cgroup_subsys *ss, struct cgroup *cont,
               struct task_struct *task)
-LL=cgroup_mutex
+(cgroup_mutex held by caller)
 
 Called prior to moving a task into a cgroup; if the subsystem
 returns an error, this will abort the attach operation.  If a NULL
@@ -489,25 +494,20 @@ remain valid while the caller holds cgroup_mutex.
 
 void attach(struct cgroup_subsys *ss, struct cgroup *cont,
            struct cgroup *old_cont, struct task_struct *task)
-LL=cgroup_mutex
-
 
 Called after the task has been attached to the cgroup, to allow any
 post-attachment activity that requires memory allocations or blocking.
 
 void fork(struct cgroup_subsy *ss, struct task_struct *task)
-LL=callback_mutex, maybe read_lock(tasklist_lock)
 
 Called when a task is forked into a cgroup. Also called during
 registration for all existing tasks.
 
 void exit(struct cgroup_subsys *ss, struct task_struct *task)
-LL=callback_mutex
 
 Called during task exit
 
 int populate(struct cgroup_subsys *ss, struct cgroup *cont)
-LL=none
 
 Called after creation of a cgroup to allow a subsystem to populate
 the cgroup directory with file entries.  The subsystem should make
@@ -524,7 +524,7 @@ example in cpusets, no task may attach before 'cpus' and 'mems' are set
 up.
 
 void bind(struct cgroup_subsys *ss, struct cgroup *root)
-LL=callback_mutex
+(cgroup_mutex held by caller)
 
 Called when a cgroup subsystem is rebound to a different hierarchy
 and root cgroup. Currently this will only involve movement between
diff --git a/Documentation/controllers/memory.txt b/Documentation/controllers/memory.txt
new file mode 100644 (file)
index 0000000..b5bbea9
--- /dev/null
@@ -0,0 +1,279 @@
+Memory Controller
+
+Salient features
+
+a. Enable control of both RSS (mapped) and Page Cache (unmapped) pages
+b. The infrastructure allows easy addition of other types of memory to control
+c. Provides *zero overhead* for non memory controller users
+d. Provides a double LRU: global memory pressure causes reclaim from the
+   global LRU; a cgroup on hitting a limit, reclaims from the per
+   cgroup LRU
+
+NOTE: Swap Cache (unmapped) is not accounted now.
+
+Benefits and Purpose of the memory controller
+
+The memory controller isolates the memory behaviour of a group of tasks
+from the rest of the system. The article on LWN [12] mentions some probable
+uses of the memory controller. The memory controller can be used to
+
+a. Isolate an application or a group of applications
+   Memory hungry applications can be isolated and limited to a smaller
+   amount of memory.
+b. Create a cgroup with limited amount of memory, this can be used
+   as a good alternative to booting with mem=XXXX.
+c. Virtualization solutions can control the amount of memory they want
+   to assign to a virtual machine instance.
+d. A CD/DVD burner could control the amount of memory used by the
+   rest of the system to ensure that burning does not fail due to lack
+   of available memory.
+e. There are several other use cases, find one or use the controller just
+   for fun (to learn and hack on the VM subsystem).
+
+1. History
+
+The memory controller has a long history. A request for comments for the memory
+controller was posted by Balbir Singh [1]. At the time the RFC was posted
+there were several implementations for memory control. The goal of the
+RFC was to build consensus and agreement for the minimal features required
+for memory control. The first RSS controller was posted by Balbir Singh[2]
+in Feb 2007. Pavel Emelianov [3][4][5] has since posted three versions of the
+RSS controller. At OLS, at the resource management BoF, everyone suggested
+that we handle both page cache and RSS together. Another request was raised
+to allow user space handling of OOM. The current memory controller is
+at version 6; it combines both mapped (RSS) and unmapped Page
+Cache Control [11].
+
+2. Memory Control
+
+Memory is a unique resource in the sense that it is present in a limited
+amount. If a task requires a lot of CPU processing, the task can spread
+its processing over a period of hours, days, months or years, but with
+memory, the same physical memory needs to be reused to accomplish the task.
+
+The memory controller implementation has been divided into phases. These
+are:
+
+1. Memory controller
+2. mlock(2) controller
+3. Kernel user memory accounting and slab control
+4. user mappings length controller
+
+The memory controller is the first controller developed.
+
+2.1. Design
+
+The core of the design is a counter called the res_counter. The res_counter
+tracks the current memory usage and limit of the group of processes associated
+with the controller. Each cgroup has a memory controller specific data
+structure (mem_cgroup) associated with it.
+
+2.2. Accounting
+
+               +--------------------+
+               |  mem_cgroup     |
+               |  (res_counter)     |
+               +--------------------+
+                /            ^      \
+               /             |       \
+           +---------------+  |        +---------------+
+           | mm_struct     |  |....    | mm_struct     |
+           |               |  |        |               |
+           +---------------+  |        +---------------+
+                              |
+                              + --------------+
+                                              |
+           +---------------+           +------+--------+
+           | page          +---------->  page_cgroup|
+           |               |           |               |
+           +---------------+           +---------------+
+
+             (Figure 1: Hierarchy of Accounting)
+
+
+Figure 1 shows the important aspects of the controller
+
+1. Accounting happens per cgroup
+2. Each mm_struct knows about which cgroup it belongs to
+3. Each page has a pointer to the page_cgroup, which in turn knows the
+   cgroup it belongs to
+
+The accounting is done as follows: mem_cgroup_charge() is invoked to setup
+the necessary data structures and check if the cgroup that is being charged
+is over its limit. If it is then reclaim is invoked on the cgroup.
+More details can be found in the reclaim section of this document.
+If everything goes well, a page meta-data-structure called page_cgroup is
+allocated and associated with the page.  This routine also adds the page to
+the per cgroup LRU.
+
+2.2.1 Accounting details
+
+All mapped pages (RSS) and unmapped user pages (Page Cache) are accounted.
+RSS pages are accounted at the time of page_add_*_rmap() unless they've already
+been accounted for earlier. A file page will be accounted for as Page Cache;
+it's mapped into the page tables of a process, duplicate accounting is carefully
+avoided. Page Cache pages are accounted at the time of add_to_page_cache().
+The corresponding routines that remove a page from the page tables or removes
+a page from Page Cache is used to decrement the accounting counters of the
+cgroup.
+
+2.3 Shared Page Accounting
+
+Shared pages are accounted on the basis of the first touch approach. The
+cgroup that first touches a page is accounted for the page. The principle
+behind this approach is that a cgroup that aggressively uses a shared
+page will eventually get charged for it (once it is uncharged from
+the cgroup that brought it in -- this will happen on memory pressure).
+
+2.4 Reclaim
+
+Each cgroup maintains a per cgroup LRU that consists of an active
+and inactive list. When a cgroup goes over its limit, we first try
+to reclaim memory from the cgroup so as to make space for the new
+pages that the cgroup has touched. If the reclaim is unsuccessful,
+an OOM routine is invoked to select and kill the bulkiest task in the
+cgroup.
+
+The reclaim algorithm has not been modified for cgroups, except that
+pages that are selected for reclaiming come from the per cgroup LRU
+list.
+
+2. Locking
+
+The memory controller uses the following hierarchy
+
+1. zone->lru_lock is used for selecting pages to be isolated
+2. mem->per_zone->lru_lock protects the per cgroup LRU (per zone)
+3. lock_page_cgroup() is used to protect page->page_cgroup
+
+3. User Interface
+
+0. Configuration
+
+a. Enable CONFIG_CGROUPS
+b. Enable CONFIG_RESOURCE_COUNTERS
+c. Enable CONFIG_CGROUP_MEM_CONT
+
+1. Prepare the cgroups
+# mkdir -p /cgroups
+# mount -t cgroup none /cgroups -o memory
+
+2. Make the new group and move bash into it
+# mkdir /cgroups/0
+# echo $$ >  /cgroups/0/tasks
+
+Since now we're in the 0 cgroup,
+We can alter the memory limit:
+# echo -n 4M > /cgroups/0/memory.limit_in_bytes
+
+NOTE: We can use a suffix (k, K, m, M, g or G) to indicate values in kilo,
+mega or gigabytes.
+
+# cat /cgroups/0/memory.limit_in_bytes
+4194304 Bytes
+
+NOTE: The interface has now changed to display the usage in bytes
+instead of pages
+
+We can check the usage:
+# cat /cgroups/0/memory.usage_in_bytes
+1216512 Bytes
+
+A successful write to this file does not guarantee a successful set of
+this limit to the value written into the file.  This can be due to a
+number of factors, such as rounding up to page boundaries or the total
+availability of memory on the system.  The user is required to re-read
+this file after a write to guarantee the value committed by the kernel.
+
+# echo -n 1 > memory.limit_in_bytes
+# cat memory.limit_in_bytes
+4096 Bytes
+
+The memory.failcnt field gives the number of times that the cgroup limit was
+exceeded.
+
+The memory.stat file gives accounting information. Now, the number of
+caches, RSS and Active pages/Inactive pages are shown.
+
+The memory.force_empty gives an interface to drop *all* charges by force.
+
+# echo -n 1 > memory.force_empty
+
+will drop all charges in cgroup. Currently, this is maintained for test.
+
+4. Testing
+
+Balbir posted lmbench, AIM9, LTP and vmmstress results [10] and [11].
+Apart from that v6 has been tested with several applications and regular
+daily use. The controller has also been tested on the PPC64, x86_64 and
+UML platforms.
+
+4.1 Troubleshooting
+
+Sometimes a user might find that the application under a cgroup is
+terminated. There are several causes for this:
+
+1. The cgroup limit is too low (just too low to do anything useful)
+2. The user is using anonymous memory and swap is turned off or too low
+
+A sync followed by echo 1 > /proc/sys/vm/drop_caches will help get rid of
+some of the pages cached in the cgroup (page cache pages).
+
+4.2 Task migration
+
+When a task migrates from one cgroup to another, it's charge is not
+carried forward. The pages allocated from the original cgroup still
+remain charged to it, the charge is dropped when the page is freed or
+reclaimed.
+
+4.3 Removing a cgroup
+
+A cgroup can be removed by rmdir, but as discussed in sections 4.1 and 4.2, a
+cgroup might have some charge associated with it, even though all
+tasks have migrated away from it. Such charges are automatically dropped at
+rmdir() if there are no tasks.
+
+4.4 Choosing what to account  -- Page Cache (unmapped) vs RSS (mapped)?
+
+The type of memory accounted by the cgroup can be limited to just
+mapped pages by writing "1" to memory.control_type field
+
+echo -n 1 > memory.control_type
+
+5. TODO
+
+1. Add support for accounting huge pages (as a separate controller)
+2. Make per-cgroup scanner reclaim not-shared pages first
+3. Teach controller to account for shared-pages
+4. Start reclamation when the limit is lowered
+5. Start reclamation in the background when the limit is
+   not yet hit but the usage is getting closer
+
+Summary
+
+Overall, the memory controller has been a stable controller and has been
+commented and discussed quite extensively in the community.
+
+References
+
+1. Singh, Balbir. RFC: Memory Controller, http://lwn.net/Articles/206697/
+2. Singh, Balbir. Memory Controller (RSS Control),
+   http://lwn.net/Articles/222762/
+3. Emelianov, Pavel. Resource controllers based on process cgroups
+   http://lkml.org/lkml/2007/3/6/198
+4. Emelianov, Pavel. RSS controller based on process cgroups (v2)
+   http://lkml.org/lkml/2007/4/9/74
+5. Emelianov, Pavel. RSS controller based on process cgroups (v3)
+   http://lkml.org/lkml/2007/5/30/244
+6. Menage, Paul. Control Groups v10, http://lwn.net/Articles/236032/
+7. Vaidyanathan, Srinivasan, Control Groups: Pagecache accounting and control
+   subsystem (v3), http://lwn.net/Articles/235534/
+8. Singh, Balbir. RSS controller V2 test results (lmbench),
+   http://lkml.org/lkml/2007/5/17/232
+9. Singh, Balbir. RSS controller V2 AIM9 results
+   http://lkml.org/lkml/2007/5/18/1
+10. Singh, Balbir. Memory controller v6 results,
+    http://lkml.org/lkml/2007/8/19/36
+11. Singh, Balbir. Memory controller v6, http://lkml.org/lkml/2007/8/17/69
+12. Corbet, Jonathan, Controlling memory use in cgroups,
+    http://lwn.net/Articles/243795/
index 141bef1c859903bdb31cada3b8e3f7745827dc57..43db6fe128142aa4ff8106e00c7686334fa07483 100644 (file)
@@ -523,21 +523,14 @@ from one cpuset to another, then the kernel will adjust the tasks
 memory placement, as above, the next time that the kernel attempts
 to allocate a page of memory for that task.
 
-If a cpuset has its CPUs modified, then each task using that
-cpuset does _not_ change its behavior automatically.  In order to
-minimize the impact on the critical scheduling code in the kernel,
-tasks will continue to use their prior CPU placement until they
-are rebound to their cpuset, by rewriting their pid to the 'tasks'
-file of their cpuset.  If a task had been bound to some subset of its
-cpuset using the sched_setaffinity() call, and if any of that subset
-is still allowed in its new cpuset settings, then the task will be
-restricted to the intersection of the CPUs it was allowed on before,
-and its new cpuset CPU placement.  If, on the other hand, there is
-no overlap between a tasks prior placement and its new cpuset CPU
-placement, then the task will be allowed to run on any CPU allowed
-in its new cpuset.  If a task is moved from one cpuset to another,
-its CPU placement is updated in the same way as if the tasks pid is
-rewritten to the 'tasks' file of its current cpuset.
+If a cpuset has its 'cpus' modified, then each task in that cpuset
+will have its allowed CPU placement changed immediately.  Similarly,
+if a tasks pid is written to a cpusets 'tasks' file, in either its
+current cpuset or another cpuset, then its allowed CPU placement is
+changed immediately.  If such a task had been bound to some subset
+of its cpuset using the sched_setaffinity() call, the task will be
+allowed to run on any CPU allowed in its new cpuset, negating the
+affect of the prior sched_setaffinity() call.
 
 In summary, the memory placement of a task whose cpuset is changed is
 updated by the kernel, on the next allocation of a page for that task,
diff --git a/Documentation/dnotify.txt b/Documentation/dnotify.txt
deleted file mode 100644 (file)
index 6984fca..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-               Linux Directory Notification
-               ============================
-
-          Stephen Rothwell <sfr@canb.auug.org.au>
-
-The intention of directory notification is to allow user applications
-to be notified when a directory, or any of the files in it, are changed.
-The basic mechanism involves the application registering for notification
-on a directory using a fcntl(2) call and the notifications themselves
-being delivered using signals.
-
-The application decides which "events" it wants to be notified about.
-The currently defined events are:
-
-       DN_ACCESS       A file in the directory was accessed (read)
-       DN_MODIFY       A file in the directory was modified (write,truncate)
-       DN_CREATE       A file was created in the directory
-       DN_DELETE       A file was unlinked from directory
-       DN_RENAME       A file in the directory was renamed
-       DN_ATTRIB       A file in the directory had its attributes
-                       changed (chmod,chown)
-
-Usually, the application must reregister after each notification, but
-if DN_MULTISHOT is or'ed with the event mask, then the registration will
-remain until explicitly removed (by registering for no events).
-
-By default, SIGIO will be delivered to the process and no other useful
-information.  However, if the F_SETSIG fcntl(2) call is used to let the
-kernel know which signal to deliver, a siginfo structure will be passed to
-the signal handler and the si_fd member of that structure will contain the
-file descriptor associated with the directory in which the event occurred.
-
-Preferably the application will choose one of the real time signals
-(SIGRTMIN + <n>) so that the notifications may be queued.  This is
-especially important if DN_MULTISHOT is specified.  Note that SIGRTMIN
-is often blocked, so it is better to use (at least) SIGRTMIN + 1.
-
-Implementation expectations (features and bugs :-))
----------------------------
-
-The notification should work for any local access to files even if the
-actual file system is on a remote server.  This implies that remote
-access to files served by local user mode servers should be notified.
-Also, remote accesses to files served by a local kernel NFS server should
-be notified.
-
-In order to make the impact on the file system code as small as possible,
-the problem of hard links to files has been ignored.  So if a file (x)
-exists in two directories (a and b) then a change to the file using the
-name "a/x" should be notified to a program expecting notifications on
-directory "a", but will not be notified to one expecting notifications on
-directory "b".
-
-Also, files that are unlinked, will still cause notifications in the
-last directory that they were linked to.
-
-Configuration
--------------
-
-Dnotify is controlled via the CONFIG_DNOTIFY configuration option.  When
-disabled, fcntl(fd, F_NOTIFY, ...) will return -EINVAL.
-
-Example
--------
-
-       #define _GNU_SOURCE     /* needed to get the defines */
-       #include <fcntl.h>      /* in glibc 2.2 this has the needed
-                                          values defined */
-       #include <signal.h>
-       #include <stdio.h>
-       #include <unistd.h>
-       
-       static volatile int event_fd;
-       
-       static void handler(int sig, siginfo_t *si, void *data)
-       {
-               event_fd = si->si_fd;
-       }
-       
-       int main(void)
-       {
-               struct sigaction act;
-               int fd;
-               
-               act.sa_sigaction = handler;
-               sigemptyset(&act.sa_mask);
-               act.sa_flags = SA_SIGINFO;
-               sigaction(SIGRTMIN + 1, &act, NULL);
-               
-               fd = open(".", O_RDONLY);
-               fcntl(fd, F_SETSIG, SIGRTMIN + 1);
-               fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
-               /* we will now be notified if any of the files
-                  in "." is modified or new files are created */
-               while (1) {
-                       pause();
-                       printf("Got event on fd=%d\n", event_fd);
-               }
-       }
diff --git a/Documentation/drivers/edac/edac.txt b/Documentation/drivers/edac/edac.txt
deleted file mode 100644 (file)
index a5c3684..0000000
+++ /dev/null
@@ -1,727 +0,0 @@
-
-
-EDAC - Error Detection And Correction
-
-Written by Doug Thompson <dougthompson@xmission.com>
-7 Dec 2005
-17 Jul 2007    Updated
-
-
-EDAC is maintained and written by:
-
-       Doug Thompson, Dave Jiang, Dave Peterson et al,
-       original author: Thayne Harbaugh,
-
-Contact:
-       website:        bluesmoke.sourceforge.net
-       mailing list:   bluesmoke-devel@lists.sourceforge.net
-
-"bluesmoke" was the name for this device driver when it was "out-of-tree"
-and maintained at sourceforge.net.  When it was pushed into 2.6.16 for the
-first time, it was renamed to 'EDAC'.
-
-The bluesmoke project at sourceforge.net is now utilized as a 'staging area'
-for EDAC development, before it is sent upstream to kernel.org
-
-At the bluesmoke/EDAC project site, is a series of quilt patches against
-recent kernels, stored in a SVN respository. For easier downloading, there
-is also a tarball snapshot available.
-
-============================================================================
-EDAC PURPOSE
-
-The 'edac' kernel module goal is to detect and report errors that occur
-within the computer system running under linux.
-
-MEMORY
-
-In the initial release, memory Correctable Errors (CE) and Uncorrectable
-Errors (UE) are the primary errors being harvested. These types of errors
-are harvested by the 'edac_mc' class of device.
-
-Detecting CE events, then harvesting those events and reporting them,
-CAN be a predictor of future UE events.  With CE events, the system can
-continue to operate, but with less safety. Preventive maintenance and
-proactive part replacement of memory DIMMs exhibiting CEs can reduce
-the likelihood of the dreaded UE events and system 'panics'.
-
-NON-MEMORY
-
-A new feature for EDAC, the edac_device class of device, was added in
-the 2.6.23 version of the kernel.
-
-This new device type allows for non-memory type of ECC hardware detectors
-to have their states harvested and presented to userspace via the sysfs
-interface.
-
-Some architectures have ECC detectors for L1, L2 and L3 caches, along with DMA
-engines, fabric switches, main data path switches, interconnections,
-and various other hardware data paths. If the hardware reports it, then
-a edac_device device probably can be constructed to harvest and present
-that to userspace.
-
-
-PCI BUS SCANNING
-
-In addition, PCI Bus Parity and SERR Errors are scanned for on PCI devices
-in order to determine if errors are occurring on data transfers.
-
-The presence of PCI Parity errors must be examined with a grain of salt.
-There are several add-in adapters that do NOT follow the PCI specification
-with regards to Parity generation and reporting. The specification says
-the vendor should tie the parity status bits to 0 if they do not intend
-to generate parity.  Some vendors do not do this, and thus the parity bit
-can "float" giving false positives.
-
-In the kernel there is a pci device attribute located in sysfs that is
-checked by the EDAC PCI scanning code. If that attribute is set,
-PCI parity/error scannining is skipped for that device. The attribute
-is:
-
-       broken_parity_status
-
-as is located in /sys/devices/pci<XXX>/0000:XX:YY.Z directorys for
-PCI devices.
-
-FUTURE HARDWARE SCANNING
-
-EDAC will have future error detectors that will be integrated with
-EDAC or added to it, in the following list:
-
-       MCE     Machine Check Exception
-       MCA     Machine Check Architecture
-       NMI     NMI notification of ECC errors
-       MSRs    Machine Specific Register error cases
-       and other mechanisms.
-
-These errors are usually bus errors, ECC errors, thermal throttling
-and the like.
-
-
-============================================================================
-EDAC VERSIONING
-
-EDAC is composed of a "core" module (edac_core.ko) and several Memory
-Controller (MC) driver modules. On a given system, the CORE
-is loaded and one MC driver will be loaded. Both the CORE and
-the MC driver (or edac_device driver) have individual versions that reflect
-current release level of their respective modules.
-
-Thus, to "report" on what version a system is running, one must report both
-the CORE's and the MC driver's versions.
-
-
-LOADING
-
-If 'edac' was statically linked with the kernel then no loading is
-necessary.  If 'edac' was built as modules then simply modprobe the
-'edac' pieces that you need.  You should be able to modprobe
-hardware-specific modules and have the dependencies load the necessary core
-modules.
-
-Example:
-
-$> modprobe amd76x_edac
-
-loads both the amd76x_edac.ko memory controller module and the edac_mc.ko
-core module.
-
-
-============================================================================
-EDAC sysfs INTERFACE
-
-EDAC presents a 'sysfs' interface for control, reporting and attribute
-reporting purposes.
-
-EDAC lives in the /sys/devices/system/edac directory.
-
-Within this directory there currently reside 2 'edac' components:
-
-       mc      memory controller(s) system
-       pci     PCI control and status system
-
-
-============================================================================
-Memory Controller (mc) Model
-
-First a background on the memory controller's model abstracted in EDAC.
-Each 'mc' device controls a set of DIMM memory modules. These modules are
-laid out in a Chip-Select Row (csrowX) and Channel table (chX). There can
-be multiple csrows and multiple channels.
-
-Memory controllers allow for several csrows, with 8 csrows being a typical value.
-Yet, the actual number of csrows depends on the electrical "loading"
-of a given motherboard, memory controller and DIMM characteristics.
-
-Dual channels allows for 128 bit data transfers to the CPU from memory.
-Some newer chipsets allow for more than 2 channels, like Fully Buffered DIMMs
-(FB-DIMMs). The following example will assume 2 channels:
-
-
-               Channel 0       Channel 1
-       ===================================
-       csrow0  | DIMM_A0       | DIMM_B0 |
-       csrow1  | DIMM_A0       | DIMM_B0 |
-       ===================================
-
-       ===================================
-       csrow2  | DIMM_A1       | DIMM_B1 |
-       csrow3  | DIMM_A1       | DIMM_B1 |
-       ===================================
-
-In the above example table there are 4 physical slots on the motherboard
-for memory DIMMs:
-
-       DIMM_A0
-       DIMM_B0
-       DIMM_A1
-       DIMM_B1
-
-Labels for these slots are usually silk screened on the motherboard. Slots
-labeled 'A' are channel 0 in this example. Slots labeled 'B'
-are channel 1. Notice that there are two csrows possible on a
-physical DIMM. These csrows are allocated their csrow assignment
-based on the slot into which the memory DIMM is placed. Thus, when 1 DIMM
-is placed in each Channel, the csrows cross both DIMMs.
-
-Memory DIMMs come single or dual "ranked". A rank is a populated csrow.
-Thus, 2 single ranked DIMMs, placed in slots DIMM_A0 and DIMM_B0 above
-will have 1 csrow, csrow0. csrow1 will be empty. On the other hand,
-when 2 dual ranked DIMMs are similarly placed, then both csrow0 and
-csrow1 will be populated. The pattern repeats itself for csrow2 and
-csrow3.
-
-The representation of the above is reflected in the directory tree
-in EDAC's sysfs interface. Starting in directory
-/sys/devices/system/edac/mc each memory controller will be represented
-by its own 'mcX' directory, where 'X" is the index of the MC.
-
-
-       ..../edac/mc/
-                  |
-                  |->mc0
-                  |->mc1
-                  |->mc2
-                  ....
-
-Under each 'mcX' directory each 'csrowX' is again represented by a
-'csrowX', where 'X" is the csrow index:
-
-
-       .../mc/mc0/
-               |
-               |->csrow0
-               |->csrow2
-               |->csrow3
-               ....
-
-Notice that there is no csrow1, which indicates that csrow0 is
-composed of a single ranked DIMMs. This should also apply in both
-Channels, in order to have dual-channel mode be operational. Since
-both csrow2 and csrow3 are populated, this indicates a dual ranked
-set of DIMMs for channels 0 and 1.
-
-
-Within each of the 'mc','mcX' and 'csrowX' directories are several
-EDAC control and attribute files.
-
-
-============================================================================
-DIRECTORY 'mc'
-
-In directory 'mc' are EDAC system overall control and attribute files:
-
-
-Panic on UE control file:
-
-       'edac_mc_panic_on_ue'
-
-       An uncorrectable error will cause a machine panic.  This is usually
-       desirable.  It is a bad idea to continue when an uncorrectable error
-       occurs - it is indeterminate what was uncorrected and the operating
-       system context might be so mangled that continuing will lead to further
-       corruption. If the kernel has MCE configured, then EDAC will never
-       notice the UE.
-
-       LOAD TIME: module/kernel parameter: panic_on_ue=[0|1]
-
-       RUN TIME:  echo "1" >/sys/devices/system/edac/mc/edac_mc_panic_on_ue
-
-
-Log UE control file:
-
-       'edac_mc_log_ue'
-
-       Generate kernel messages describing uncorrectable errors.  These errors
-       are reported through the system message log system.  UE statistics
-       will be accumulated even when UE logging is disabled.
-
-       LOAD TIME: module/kernel parameter: log_ue=[0|1]
-
-       RUN TIME: echo "1" >/sys/devices/system/edac/mc/edac_mc_log_ue
-
-
-Log CE control file:
-
-       'edac_mc_log_ce'
-
-       Generate kernel messages describing correctable errors.  These
-       errors are reported through the system message log system.
-       CE statistics will be accumulated even when CE logging is disabled.
-
-       LOAD TIME: module/kernel parameter: log_ce=[0|1]
-
-       RUN TIME: echo "1" >/sys/devices/system/edac/mc/edac_mc_log_ce
-
-
-Polling period control file:
-
-       'edac_mc_poll_msec'
-
-       The time period, in milliseconds, for polling for error information.
-       Too small a value wastes resources.  Too large a value might delay
-       necessary handling of errors and might loose valuable information for
-       locating the error.  1000 milliseconds (once each second) is the current
-       default. Systems which require all the bandwidth they can get, may
-       increase this.
-
-       LOAD TIME: module/kernel parameter: poll_msec=[0|1]
-
-       RUN TIME: echo "1000" >/sys/devices/system/edac/mc/edac_mc_poll_msec
-
-
-============================================================================
-'mcX' DIRECTORIES
-
-
-In 'mcX' directories are EDAC control and attribute files for
-this 'X" instance of the memory controllers:
-
-
-Counter reset control file:
-
-       'reset_counters'
-
-       This write-only control file will zero all the statistical counters
-       for UE and CE errors.  Zeroing the counters will also reset the timer
-       indicating how long since the last counter zero.  This is useful
-       for computing errors/time.  Since the counters are always reset at
-       driver initialization time, no module/kernel parameter is available.
-
-       RUN TIME: echo "anything" >/sys/devices/system/edac/mc/mc0/counter_reset
-
-               This resets the counters on memory controller 0
-
-
-Seconds since last counter reset control file:
-
-       'seconds_since_reset'
-
-       This attribute file displays how many seconds have elapsed since the
-       last counter reset. This can be used with the error counters to
-       measure error rates.
-
-
-
-Memory Controller name attribute file:
-
-       'mc_name'
-
-       This attribute file displays the type of memory controller
-       that is being utilized.
-
-
-Total memory managed by this memory controller attribute file:
-
-       'size_mb'
-
-       This attribute file displays, in count of megabytes, of memory
-       that this instance of memory controller manages.
-
-
-Total Uncorrectable Errors count attribute file:
-
-       'ue_count'
-
-       This attribute file displays the total count of uncorrectable
-       errors that have occurred on this memory controller. If panic_on_ue
-       is set this counter will not have a chance to increment,
-       since EDAC will panic the system.
-
-
-Total UE count that had no information attribute fileY:
-
-       'ue_noinfo_count'
-
-       This attribute file displays the number of UEs that
-       have occurred have occurred with  no informations as to which DIMM
-       slot is having errors.
-
-
-Total Correctable Errors count attribute file:
-
-       'ce_count'
-
-       This attribute file displays the total count of correctable
-       errors that have occurred on this memory controller. This
-       count is very important to examine. CEs provide early
-       indications that a DIMM is beginning to fail. This count
-       field should be monitored for non-zero values and report
-       such information to the system administrator.
-
-
-Total Correctable Errors count attribute file:
-
-       'ce_noinfo_count'
-
-       This attribute file displays the number of CEs that
-       have occurred wherewith no informations as to which DIMM slot
-       is having errors. Memory is handicapped, but operational,
-       yet no information is available to indicate which slot
-       the failing memory is in. This count field should be also
-       be monitored for non-zero values.
-
-Device Symlink:
-
-       'device'
-
-       Symlink to the memory controller device.
-
-Sdram memory scrubbing rate:
-
-       'sdram_scrub_rate'
-
-       Read/Write attribute file that controls memory scrubbing. The scrubbing
-       rate is set by writing a minimum bandwith in bytes/sec to the attribute
-       file. The rate will be translated to an internal value that gives at
-       least the specified rate.
-
-       Reading the file will return the actual scrubbing rate employed.
-
-       If configuration fails or memory scrubbing is not implemented, the value
-       of the attribute file will be -1.
-
-
-
-============================================================================
-'csrowX' DIRECTORIES
-
-In the 'csrowX' directories are EDAC control and attribute files for
-this 'X" instance of csrow:
-
-
-Total Uncorrectable Errors count attribute file:
-
-       'ue_count'
-
-       This attribute file displays the total count of uncorrectable
-       errors that have occurred on this csrow. If panic_on_ue is set
-       this counter will not have a chance to increment, since EDAC
-       will panic the system.
-
-
-Total Correctable Errors count attribute file:
-
-       'ce_count'
-
-       This attribute file displays the total count of correctable
-       errors that have occurred on this csrow. This
-       count is very important to examine. CEs provide early
-       indications that a DIMM is beginning to fail. This count
-       field should be monitored for non-zero values and report
-       such information to the system administrator.
-
-
-Total memory managed by this csrow attribute file:
-
-       'size_mb'
-
-       This attribute file displays, in count of megabytes, of memory
-       that this csrow contains.
-
-
-Memory Type attribute file:
-
-       'mem_type'
-
-       This attribute file will display what type of memory is currently
-       on this csrow. Normally, either buffered or unbuffered memory.
-       Examples:
-               Registered-DDR
-               Unbuffered-DDR
-
-
-EDAC Mode of operation attribute file:
-
-       'edac_mode'
-
-       This attribute file will display what type of Error detection
-       and correction is being utilized.
-
-
-Device type attribute file:
-
-       'dev_type'
-
-       This attribute file will display what type of DRAM device is
-       being utilized on this DIMM.
-       Examples:
-               x1
-               x2
-               x4
-               x8
-
-
-Channel 0 CE Count attribute file:
-
-       'ch0_ce_count'
-
-       This attribute file will display the count of CEs on this
-       DIMM located in channel 0.
-
-
-Channel 0 UE Count attribute file:
-
-       'ch0_ue_count'
-
-       This attribute file will display the count of UEs on this
-       DIMM located in channel 0.
-
-
-Channel 0 DIMM Label control file:
-
-       'ch0_dimm_label'
-
-       This control file allows this DIMM to have a label assigned
-       to it. With this label in the module, when errors occur
-       the output can provide the DIMM label in the system log.
-       This becomes vital for panic events to isolate the
-       cause of the UE event.
-
-       DIMM Labels must be assigned after booting, with information
-       that correctly identifies the physical slot with its
-       silk screen label. This information is currently very
-       motherboard specific and determination of this information
-       must occur in userland at this time.
-
-
-Channel 1 CE Count attribute file:
-
-       'ch1_ce_count'
-
-       This attribute file will display the count of CEs on this
-       DIMM located in channel 1.
-
-
-Channel 1 UE Count attribute file:
-
-       'ch1_ue_count'
-
-       This attribute file will display the count of UEs on this
-       DIMM located in channel 0.
-
-
-Channel 1 DIMM Label control file:
-
-       'ch1_dimm_label'
-
-       This control file allows this DIMM to have a label assigned
-       to it. With this label in the module, when errors occur
-       the output can provide the DIMM label in the system log.
-       This becomes vital for panic events to isolate the
-       cause of the UE event.
-
-       DIMM Labels must be assigned after booting, with information
-       that correctly identifies the physical slot with its
-       silk screen label. This information is currently very
-       motherboard specific and determination of this information
-       must occur in userland at this time.
-
-
-============================================================================
-SYSTEM LOGGING
-
-If logging for UEs and CEs are enabled then system logs will have
-error notices indicating errors that have been detected:
-
-EDAC MC0: CE page 0x283, offset 0xce0, grain 8, syndrome 0x6ec3, row 0,
-channel 1 "DIMM_B1": amd76x_edac
-
-EDAC MC0: CE page 0x1e5, offset 0xfb0, grain 8, syndrome 0xb741, row 0,
-channel 1 "DIMM_B1": amd76x_edac
-
-
-The structure of the message is:
-       the memory controller                   (MC0)
-       Error type                              (CE)
-       memory page                             (0x283)
-       offset in the page                      (0xce0)
-       the byte granularity                    (grain 8)
-               or resolution of the error
-       the error syndrome                      (0xb741)
-       memory row                              (row 0)
-       memory channel                          (channel 1)
-       DIMM label, if set prior                (DIMM B1
-       and then an optional, driver-specific message that may
-               have additional information.
-
-Both UEs and CEs with no info will lack all but memory controller,
-error type, a notice of "no info" and then an optional,
-driver-specific error message.
-
-
-
-============================================================================
-PCI Bus Parity Detection
-
-
-On Header Type 00 devices the primary status is looked at
-for any parity error regardless of whether Parity is enabled on the
-device.  (The spec indicates parity is generated in some cases).
-On Header Type 01 bridges, the secondary status register is also
-looked at to see if parity occurred on the bus on the other side of
-the bridge.
-
-
-SYSFS CONFIGURATION
-
-Under /sys/devices/system/edac/pci are control and attribute files as follows:
-
-
-Enable/Disable PCI Parity checking control file:
-
-       'check_pci_parity'
-
-
-       This control file enables or disables the PCI Bus Parity scanning
-       operation. Writing a 1 to this file enables the scanning. Writing
-       a 0 to this file disables the scanning.
-
-       Enable:
-       echo "1" >/sys/devices/system/edac/pci/check_pci_parity
-
-       Disable:
-       echo "0" >/sys/devices/system/edac/pci/check_pci_parity
-
-
-
-Panic on PCI PARITY Error:
-
-       'panic_on_pci_parity'
-
-
-       This control files enables or disables panicking when a parity
-       error has been detected.
-
-
-       module/kernel parameter: panic_on_pci_parity=[0|1]
-
-       Enable:
-       echo "1" >/sys/devices/system/edac/pci/panic_on_pci_parity
-
-       Disable:
-       echo "0" >/sys/devices/system/edac/pci/panic_on_pci_parity
-
-
-Parity Count:
-
-       'pci_parity_count'
-
-       This attribute file will display the number of parity errors that
-       have been detected.
-
-
-
-=======================================================================
-
-
-EDAC_DEVICE type of device
-
-In the header file, edac_core.h, there is a series of edac_device structures
-and APIs for the EDAC_DEVICE.
-
-User space access to an edac_device is through the sysfs interface.
-
-At the location /sys/devices/system/edac (sysfs) new edac_device devices will
-appear.
-
-There is a three level tree beneath the above 'edac' directory. For example,
-the 'test_device_edac' device (found at the bluesmoke.sourceforget.net website)
-installs itself as:
-
-       /sys/devices/systm/edac/test-instance
-
-in this directory are various controls, a symlink and one or more 'instance'
-directorys.
-
-The standard default controls are:
-
-       log_ce          boolean to log CE events
-       log_ue          boolean to log UE events
-       panic_on_ue     boolean to 'panic' the system if an UE is encountered
-                       (default off, can be set true via startup script)
-       poll_msec       time period between POLL cycles for events
-
-The test_device_edac device adds at least one of its own custom control:
-
-       test_bits       which in the current test driver does nothing but
-                       show how it is installed. A ported driver can
-                       add one or more such controls and/or attributes
-                       for specific uses.
-                       One out-of-tree driver uses controls here to allow
-                       for ERROR INJECTION operations to hardware
-                       injection registers
-
-The symlink points to the 'struct dev' that is registered for this edac_device.
-
-INSTANCES
-
-One or more instance directories are present. For the 'test_device_edac' case:
-
-       test-instance0
-
-
-In this directory there are two default counter attributes, which are totals of
-counter in deeper subdirectories.
-
-       ce_count        total of CE events of subdirectories
-       ue_count        total of UE events of subdirectories
-
-BLOCKS
-
-At the lowest directory level is the 'block' directory. There can be 0, 1
-or more blocks specified in each instance.
-
-       test-block0
-
-
-In this directory the default attributes are:
-
-       ce_count        which is counter of CE events for this 'block'
-                       of hardware being monitored
-       ue_count        which is counter of UE events for this 'block'
-                       of hardware being monitored
-
-
-The 'test_device_edac' device adds 4 attributes and 1 control:
-
-       test-block-bits-0       for every POLL cycle this counter
-                               is incremented
-       test-block-bits-1       every 10 cycles, this counter is bumped once,
-                               and test-block-bits-0 is set to 0
-       test-block-bits-2       every 100 cycles, this counter is bumped once,
-                               and test-block-bits-1 is set to 0
-       test-block-bits-3       every 1000 cycles, this counter is bumped once,
-                               and test-block-bits-2 is set to 0
-
-
-       reset-counters          writing ANY thing to this control will
-                               reset all the above counters.
-
-
-Use of the 'test_device_edac' driver should any others to create their own
-unique drivers for their hardware systems.
-
-The 'test_device_edac' sample driver is located at the
-bluesmoke.sourceforge.net project site for EDAC.
-
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
new file mode 100644 (file)
index 0000000..a5c3684
--- /dev/null
@@ -0,0 +1,727 @@
+
+
+EDAC - Error Detection And Correction
+
+Written by Doug Thompson <dougthompson@xmission.com>
+7 Dec 2005
+17 Jul 2007    Updated
+
+
+EDAC is maintained and written by:
+
+       Doug Thompson, Dave Jiang, Dave Peterson et al,
+       original author: Thayne Harbaugh,
+
+Contact:
+       website:        bluesmoke.sourceforge.net
+       mailing list:   bluesmoke-devel@lists.sourceforge.net
+
+"bluesmoke" was the name for this device driver when it was "out-of-tree"
+and maintained at sourceforge.net.  When it was pushed into 2.6.16 for the
+first time, it was renamed to 'EDAC'.
+
+The bluesmoke project at sourceforge.net is now utilized as a 'staging area'
+for EDAC development, before it is sent upstream to kernel.org
+
+At the bluesmoke/EDAC project site, is a series of quilt patches against
+recent kernels, stored in a SVN respository. For easier downloading, there
+is also a tarball snapshot available.
+
+============================================================================
+EDAC PURPOSE
+
+The 'edac' kernel module goal is to detect and report errors that occur
+within the computer system running under linux.
+
+MEMORY
+
+In the initial release, memory Correctable Errors (CE) and Uncorrectable
+Errors (UE) are the primary errors being harvested. These types of errors
+are harvested by the 'edac_mc' class of device.
+
+Detecting CE events, then harvesting those events and reporting them,
+CAN be a predictor of future UE events.  With CE events, the system can
+continue to operate, but with less safety. Preventive maintenance and
+proactive part replacement of memory DIMMs exhibiting CEs can reduce
+the likelihood of the dreaded UE events and system 'panics'.
+
+NON-MEMORY
+
+A new feature for EDAC, the edac_device class of device, was added in
+the 2.6.23 version of the kernel.
+
+This new device type allows for non-memory type of ECC hardware detectors
+to have their states harvested and presented to userspace via the sysfs
+interface.
+
+Some architectures have ECC detectors for L1, L2 and L3 caches, along with DMA
+engines, fabric switches, main data path switches, interconnections,
+and various other hardware data paths. If the hardware reports it, then
+a edac_device device probably can be constructed to harvest and present
+that to userspace.
+
+
+PCI BUS SCANNING
+
+In addition, PCI Bus Parity and SERR Errors are scanned for on PCI devices
+in order to determine if errors are occurring on data transfers.
+
+The presence of PCI Parity errors must be examined with a grain of salt.
+There are several add-in adapters that do NOT follow the PCI specification
+with regards to Parity generation and reporting. The specification says
+the vendor should tie the parity status bits to 0 if they do not intend
+to generate parity.  Some vendors do not do this, and thus the parity bit
+can "float" giving false positives.
+
+In the kernel there is a pci device attribute located in sysfs that is
+checked by the EDAC PCI scanning code. If that attribute is set,
+PCI parity/error scannining is skipped for that device. The attribute
+is:
+
+       broken_parity_status
+
+as is located in /sys/devices/pci<XXX>/0000:XX:YY.Z directorys for
+PCI devices.
+
+FUTURE HARDWARE SCANNING
+
+EDAC will have future error detectors that will be integrated with
+EDAC or added to it, in the following list:
+
+       MCE     Machine Check Exception
+       MCA     Machine Check Architecture
+       NMI     NMI notification of ECC errors
+       MSRs    Machine Specific Register error cases
+       and other mechanisms.
+
+These errors are usually bus errors, ECC errors, thermal throttling
+and the like.
+
+
+============================================================================
+EDAC VERSIONING
+
+EDAC is composed of a "core" module (edac_core.ko) and several Memory
+Controller (MC) driver modules. On a given system, the CORE
+is loaded and one MC driver will be loaded. Both the CORE and
+the MC driver (or edac_device driver) have individual versions that reflect
+current release level of their respective modules.
+
+Thus, to "report" on what version a system is running, one must report both
+the CORE's and the MC driver's versions.
+
+
+LOADING
+
+If 'edac' was statically linked with the kernel then no loading is
+necessary.  If 'edac' was built as modules then simply modprobe the
+'edac' pieces that you need.  You should be able to modprobe
+hardware-specific modules and have the dependencies load the necessary core
+modules.
+
+Example:
+
+$> modprobe amd76x_edac
+
+loads both the amd76x_edac.ko memory controller module and the edac_mc.ko
+core module.
+
+
+============================================================================
+EDAC sysfs INTERFACE
+
+EDAC presents a 'sysfs' interface for control, reporting and attribute
+reporting purposes.
+
+EDAC lives in the /sys/devices/system/edac directory.
+
+Within this directory there currently reside 2 'edac' components:
+
+       mc      memory controller(s) system
+       pci     PCI control and status system
+
+
+============================================================================
+Memory Controller (mc) Model
+
+First a background on the memory controller's model abstracted in EDAC.
+Each 'mc' device controls a set of DIMM memory modules. These modules are
+laid out in a Chip-Select Row (csrowX) and Channel table (chX). There can
+be multiple csrows and multiple channels.
+
+Memory controllers allow for several csrows, with 8 csrows being a typical value.
+Yet, the actual number of csrows depends on the electrical "loading"
+of a given motherboard, memory controller and DIMM characteristics.
+
+Dual channels allows for 128 bit data transfers to the CPU from memory.
+Some newer chipsets allow for more than 2 channels, like Fully Buffered DIMMs
+(FB-DIMMs). The following example will assume 2 channels:
+
+
+               Channel 0       Channel 1
+       ===================================
+       csrow0  | DIMM_A0       | DIMM_B0 |
+       csrow1  | DIMM_A0       | DIMM_B0 |
+       ===================================
+
+       ===================================
+       csrow2  | DIMM_A1       | DIMM_B1 |
+       csrow3  | DIMM_A1       | DIMM_B1 |
+       ===================================
+
+In the above example table there are 4 physical slots on the motherboard
+for memory DIMMs:
+
+       DIMM_A0
+       DIMM_B0
+       DIMM_A1
+       DIMM_B1
+
+Labels for these slots are usually silk screened on the motherboard. Slots
+labeled 'A' are channel 0 in this example. Slots labeled 'B'
+are channel 1. Notice that there are two csrows possible on a
+physical DIMM. These csrows are allocated their csrow assignment
+based on the slot into which the memory DIMM is placed. Thus, when 1 DIMM
+is placed in each Channel, the csrows cross both DIMMs.
+
+Memory DIMMs come single or dual "ranked". A rank is a populated csrow.
+Thus, 2 single ranked DIMMs, placed in slots DIMM_A0 and DIMM_B0 above
+will have 1 csrow, csrow0. csrow1 will be empty. On the other hand,
+when 2 dual ranked DIMMs are similarly placed, then both csrow0 and
+csrow1 will be populated. The pattern repeats itself for csrow2 and
+csrow3.
+
+The representation of the above is reflected in the directory tree
+in EDAC's sysfs interface. Starting in directory
+/sys/devices/system/edac/mc each memory controller will be represented
+by its own 'mcX' directory, where 'X" is the index of the MC.
+
+
+       ..../edac/mc/
+                  |
+                  |->mc0
+                  |->mc1
+                  |->mc2
+                  ....
+
+Under each 'mcX' directory each 'csrowX' is again represented by a
+'csrowX', where 'X" is the csrow index:
+
+
+       .../mc/mc0/
+               |
+               |->csrow0
+               |->csrow2
+               |->csrow3
+               ....
+
+Notice that there is no csrow1, which indicates that csrow0 is
+composed of a single ranked DIMMs. This should also apply in both
+Channels, in order to have dual-channel mode be operational. Since
+both csrow2 and csrow3 are populated, this indicates a dual ranked
+set of DIMMs for channels 0 and 1.
+
+
+Within each of the 'mc','mcX' and 'csrowX' directories are several
+EDAC control and attribute files.
+
+
+============================================================================
+DIRECTORY 'mc'
+
+In directory 'mc' are EDAC system overall control and attribute files:
+
+
+Panic on UE control file:
+
+       'edac_mc_panic_on_ue'
+
+       An uncorrectable error will cause a machine panic.  This is usually
+       desirable.  It is a bad idea to continue when an uncorrectable error
+       occurs - it is indeterminate what was uncorrected and the operating
+       system context might be so mangled that continuing will lead to further
+       corruption. If the kernel has MCE configured, then EDAC will never
+       notice the UE.
+
+       LOAD TIME: module/kernel parameter: panic_on_ue=[0|1]
+
+       RUN TIME:  echo "1" >/sys/devices/system/edac/mc/edac_mc_panic_on_ue
+
+
+Log UE control file:
+
+       'edac_mc_log_ue'
+
+       Generate kernel messages describing uncorrectable errors.  These errors
+       are reported through the system message log system.  UE statistics
+       will be accumulated even when UE logging is disabled.
+
+       LOAD TIME: module/kernel parameter: log_ue=[0|1]
+
+       RUN TIME: echo "1" >/sys/devices/system/edac/mc/edac_mc_log_ue
+
+
+Log CE control file:
+
+       'edac_mc_log_ce'
+
+       Generate kernel messages describing correctable errors.  These
+       errors are reported through the system message log system.
+       CE statistics will be accumulated even when CE logging is disabled.
+
+       LOAD TIME: module/kernel parameter: log_ce=[0|1]
+
+       RUN TIME: echo "1" >/sys/devices/system/edac/mc/edac_mc_log_ce
+
+
+Polling period control file:
+
+       'edac_mc_poll_msec'
+
+       The time period, in milliseconds, for polling for error information.
+       Too small a value wastes resources.  Too large a value might delay
+       necessary handling of errors and might loose valuable information for
+       locating the error.  1000 milliseconds (once each second) is the current
+       default. Systems which require all the bandwidth they can get, may
+       increase this.
+
+       LOAD TIME: module/kernel parameter: poll_msec=[0|1]
+
+       RUN TIME: echo "1000" >/sys/devices/system/edac/mc/edac_mc_poll_msec
+
+
+============================================================================
+'mcX' DIRECTORIES
+
+
+In 'mcX' directories are EDAC control and attribute files for
+this 'X" instance of the memory controllers:
+
+
+Counter reset control file:
+
+       'reset_counters'
+
+       This write-only control file will zero all the statistical counters
+       for UE and CE errors.  Zeroing the counters will also reset the timer
+       indicating how long since the last counter zero.  This is useful
+       for computing errors/time.  Since the counters are always reset at
+       driver initialization time, no module/kernel parameter is available.
+
+       RUN TIME: echo "anything" >/sys/devices/system/edac/mc/mc0/counter_reset
+
+               This resets the counters on memory controller 0
+
+
+Seconds since last counter reset control file:
+
+       'seconds_since_reset'
+
+       This attribute file displays how many seconds have elapsed since the
+       last counter reset. This can be used with the error counters to
+       measure error rates.
+
+
+
+Memory Controller name attribute file:
+
+       'mc_name'
+
+       This attribute file displays the type of memory controller
+       that is being utilized.
+
+
+Total memory managed by this memory controller attribute file:
+
+       'size_mb'
+
+       This attribute file displays, in count of megabytes, of memory
+       that this instance of memory controller manages.
+
+
+Total Uncorrectable Errors count attribute file:
+
+       'ue_count'
+
+       This attribute file displays the total count of uncorrectable
+       errors that have occurred on this memory controller. If panic_on_ue
+       is set this counter will not have a chance to increment,
+       since EDAC will panic the system.
+
+
+Total UE count that had no information attribute fileY:
+
+       'ue_noinfo_count'
+
+       This attribute file displays the number of UEs that
+       have occurred have occurred with  no informations as to which DIMM
+       slot is having errors.
+
+
+Total Correctable Errors count attribute file:
+
+       'ce_count'
+
+       This attribute file displays the total count of correctable
+       errors that have occurred on this memory controller. This
+       count is very important to examine. CEs provide early
+       indications that a DIMM is beginning to fail. This count
+       field should be monitored for non-zero values and report
+       such information to the system administrator.
+
+
+Total Correctable Errors count attribute file:
+
+       'ce_noinfo_count'
+
+       This attribute file displays the number of CEs that
+       have occurred wherewith no informations as to which DIMM slot
+       is having errors. Memory is handicapped, but operational,
+       yet no information is available to indicate which slot
+       the failing memory is in. This count field should be also
+       be monitored for non-zero values.
+
+Device Symlink:
+
+       'device'
+
+       Symlink to the memory controller device.
+
+Sdram memory scrubbing rate:
+
+       'sdram_scrub_rate'
+
+       Read/Write attribute file that controls memory scrubbing. The scrubbing
+       rate is set by writing a minimum bandwith in bytes/sec to the attribute
+       file. The rate will be translated to an internal value that gives at
+       least the specified rate.
+
+       Reading the file will return the actual scrubbing rate employed.
+
+       If configuration fails or memory scrubbing is not implemented, the value
+       of the attribute file will be -1.
+
+
+
+============================================================================
+'csrowX' DIRECTORIES
+
+In the 'csrowX' directories are EDAC control and attribute files for
+this 'X" instance of csrow:
+
+
+Total Uncorrectable Errors count attribute file:
+
+       'ue_count'
+
+       This attribute file displays the total count of uncorrectable
+       errors that have occurred on this csrow. If panic_on_ue is set
+       this counter will not have a chance to increment, since EDAC
+       will panic the system.
+
+
+Total Correctable Errors count attribute file:
+
+       'ce_count'
+
+       This attribute file displays the total count of correctable
+       errors that have occurred on this csrow. This
+       count is very important to examine. CEs provide early
+       indications that a DIMM is beginning to fail. This count
+       field should be monitored for non-zero values and report
+       such information to the system administrator.
+
+
+Total memory managed by this csrow attribute file:
+
+       'size_mb'
+
+       This attribute file displays, in count of megabytes, of memory
+       that this csrow contains.
+
+
+Memory Type attribute file:
+
+       'mem_type'
+
+       This attribute file will display what type of memory is currently
+       on this csrow. Normally, either buffered or unbuffered memory.
+       Examples:
+               Registered-DDR
+               Unbuffered-DDR
+
+
+EDAC Mode of operation attribute file:
+
+       'edac_mode'
+
+       This attribute file will display what type of Error detection
+       and correction is being utilized.
+
+
+Device type attribute file:
+
+       'dev_type'
+
+       This attribute file will display what type of DRAM device is
+       being utilized on this DIMM.
+       Examples:
+               x1
+               x2
+               x4
+               x8
+
+
+Channel 0 CE Count attribute file:
+
+       'ch0_ce_count'
+
+       This attribute file will display the count of CEs on this
+       DIMM located in channel 0.
+
+
+Channel 0 UE Count attribute file:
+
+       'ch0_ue_count'
+
+       This attribute file will display the count of UEs on this
+       DIMM located in channel 0.
+
+
+Channel 0 DIMM Label control file:
+
+       'ch0_dimm_label'
+
+       This control file allows this DIMM to have a label assigned
+       to it. With this label in the module, when errors occur
+       the output can provide the DIMM label in the system log.
+       This becomes vital for panic events to isolate the
+       cause of the UE event.
+
+       DIMM Labels must be assigned after booting, with information
+       that correctly identifies the physical slot with its
+       silk screen label. This information is currently very
+       motherboard specific and determination of this information
+       must occur in userland at this time.
+
+
+Channel 1 CE Count attribute file:
+
+       'ch1_ce_count'
+
+       This attribute file will display the count of CEs on this
+       DIMM located in channel 1.
+
+
+Channel 1 UE Count attribute file:
+
+       'ch1_ue_count'
+
+       This attribute file will display the count of UEs on this
+       DIMM located in channel 0.
+
+
+Channel 1 DIMM Label control file:
+
+       'ch1_dimm_label'
+
+       This control file allows this DIMM to have a label assigned
+       to it. With this label in the module, when errors occur
+       the output can provide the DIMM label in the system log.
+       This becomes vital for panic events to isolate the
+       cause of the UE event.
+
+       DIMM Labels must be assigned after booting, with information
+       that correctly identifies the physical slot with its
+       silk screen label. This information is currently very
+       motherboard specific and determination of this information
+       must occur in userland at this time.
+
+
+============================================================================
+SYSTEM LOGGING
+
+If logging for UEs and CEs are enabled then system logs will have
+error notices indicating errors that have been detected:
+
+EDAC MC0: CE page 0x283, offset 0xce0, grain 8, syndrome 0x6ec3, row 0,
+channel 1 "DIMM_B1": amd76x_edac
+
+EDAC MC0: CE page 0x1e5, offset 0xfb0, grain 8, syndrome 0xb741, row 0,
+channel 1 "DIMM_B1": amd76x_edac
+
+
+The structure of the message is:
+       the memory controller                   (MC0)
+       Error type                              (CE)
+       memory page                             (0x283)
+       offset in the page                      (0xce0)
+       the byte granularity                    (grain 8)
+               or resolution of the error
+       the error syndrome                      (0xb741)
+       memory row                              (row 0)
+       memory channel                          (channel 1)
+       DIMM label, if set prior                (DIMM B1
+       and then an optional, driver-specific message that may
+               have additional information.
+
+Both UEs and CEs with no info will lack all but memory controller,
+error type, a notice of "no info" and then an optional,
+driver-specific error message.
+
+
+
+============================================================================
+PCI Bus Parity Detection
+
+
+On Header Type 00 devices the primary status is looked at
+for any parity error regardless of whether Parity is enabled on the
+device.  (The spec indicates parity is generated in some cases).
+On Header Type 01 bridges, the secondary status register is also
+looked at to see if parity occurred on the bus on the other side of
+the bridge.
+
+
+SYSFS CONFIGURATION
+
+Under /sys/devices/system/edac/pci are control and attribute files as follows:
+
+
+Enable/Disable PCI Parity checking control file:
+
+       'check_pci_parity'
+
+
+       This control file enables or disables the PCI Bus Parity scanning
+       operation. Writing a 1 to this file enables the scanning. Writing
+       a 0 to this file disables the scanning.
+
+       Enable:
+       echo "1" >/sys/devices/system/edac/pci/check_pci_parity
+
+       Disable:
+       echo "0" >/sys/devices/system/edac/pci/check_pci_parity
+
+
+
+Panic on PCI PARITY Error:
+
+       'panic_on_pci_parity'
+
+
+       This control files enables or disables panicking when a parity
+       error has been detected.
+
+
+       module/kernel parameter: panic_on_pci_parity=[0|1]
+
+       Enable:
+       echo "1" >/sys/devices/system/edac/pci/panic_on_pci_parity
+
+       Disable:
+       echo "0" >/sys/devices/system/edac/pci/panic_on_pci_parity
+
+
+Parity Count:
+
+       'pci_parity_count'
+
+       This attribute file will display the number of parity errors that
+       have been detected.
+
+
+
+=======================================================================
+
+
+EDAC_DEVICE type of device
+
+In the header file, edac_core.h, there is a series of edac_device structures
+and APIs for the EDAC_DEVICE.
+
+User space access to an edac_device is through the sysfs interface.
+
+At the location /sys/devices/system/edac (sysfs) new edac_device devices will
+appear.
+
+There is a three level tree beneath the above 'edac' directory. For example,
+the 'test_device_edac' device (found at the bluesmoke.sourceforget.net website)
+installs itself as:
+
+       /sys/devices/systm/edac/test-instance
+
+in this directory are various controls, a symlink and one or more 'instance'
+directorys.
+
+The standard default controls are:
+
+       log_ce          boolean to log CE events
+       log_ue          boolean to log UE events
+       panic_on_ue     boolean to 'panic' the system if an UE is encountered
+                       (default off, can be set true via startup script)
+       poll_msec       time period between POLL cycles for events
+
+The test_device_edac device adds at least one of its own custom control:
+
+       test_bits       which in the current test driver does nothing but
+                       show how it is installed. A ported driver can
+                       add one or more such controls and/or attributes
+                       for specific uses.
+                       One out-of-tree driver uses controls here to allow
+                       for ERROR INJECTION operations to hardware
+                       injection registers
+
+The symlink points to the 'struct dev' that is registered for this edac_device.
+
+INSTANCES
+
+One or more instance directories are present. For the 'test_device_edac' case:
+
+       test-instance0
+
+
+In this directory there are two default counter attributes, which are totals of
+counter in deeper subdirectories.
+
+       ce_count        total of CE events of subdirectories
+       ue_count        total of UE events of subdirectories
+
+BLOCKS
+
+At the lowest directory level is the 'block' directory. There can be 0, 1
+or more blocks specified in each instance.
+
+       test-block0
+
+
+In this directory the default attributes are:
+
+       ce_count        which is counter of CE events for this 'block'
+                       of hardware being monitored
+       ue_count        which is counter of UE events for this 'block'
+                       of hardware being monitored
+
+
+The 'test_device_edac' device adds 4 attributes and 1 control:
+
+       test-block-bits-0       for every POLL cycle this counter
+                               is incremented
+       test-block-bits-1       every 10 cycles, this counter is bumped once,
+                               and test-block-bits-0 is set to 0
+       test-block-bits-2       every 100 cycles, this counter is bumped once,
+                               and test-block-bits-1 is set to 0
+       test-block-bits-3       every 1000 cycles, this counter is bumped once,
+                               and test-block-bits-2 is set to 0
+
+
+       reset-counters          writing ANY thing to this control will
+                               reset all the above counters.
+
+
+Use of the 'test_device_edac' driver should any others to create their own
+unique drivers for their hardware systems.
+
+The 'test_device_edac' sample driver is located at the
+bluesmoke.sourceforge.net project site for EDAC.
+
index 113165b48305740e31cd5519f8d1a605f9e1ca0e..2ebb94d6ed8e547d5cb84cdc6feeba126388baf3 100644 (file)
@@ -170,7 +170,6 @@ Sylpheed (GUI)
 
 - Works well for inlining text (or using attachments).
 - Allows use of an external editor.
-- Not good for IMAP.
 - Is slow on large folders.
 - Won't do TLS SMTP auth over a non-SSL connection.
 - Has a helpful ruler bar in the compose window.
index 63883a892120e125be75db301e1c49322c1c7a71..74832837025032dcd0f4ee21a665b3a59612b701 100644 (file)
@@ -7,10 +7,10 @@ IO. The following example may be a useful explanation of how one such setup
 works:
 
 - userspace app like Xfbdev mmaps framebuffer
-- deferred IO and driver sets up nopage and page_mkwrite handlers
+- deferred IO and driver sets up fault and page_mkwrite handlers
 - userspace app tries to write to mmaped vaddress
-- we get pagefault and reach nopage handler
-- nopage handler finds and returns physical page
+- we get pagefault and reach fault handler
+- fault handler finds and returns physical page
 - we get page_mkwrite where we add this page to a list
 - schedule a workqueue task to be run after a delay
 - app continues writing to that page with no additional cost. this is
index a7d9d179131a76c1f3ef297792ddaae95786e283..17b1659bd3f8d6975245e9a99caddfda31aef7da 100644 (file)
@@ -6,14 +6,6 @@ be removed from this file.
 
 ---------------------------
 
-What:  MXSER
-When:  December 2007
-Why:   Old mxser driver is obsoleted by the mxser_new. Give it some time yet
-       and remove it.
-Who:   Jiri Slaby <jirislaby@gmail.com>
-
----------------------------
-
 What:  dev->power.power_state
 When:  July 2007
 Why:   Broken design for runtime control over driver power states, confusing
@@ -208,13 +200,6 @@ Who:       Randy Dunlap <randy.dunlap@oracle.com>
 
 ---------------------------
 
-What:  drivers depending on OSS_OBSOLETE
-When:  options in 2.6.23, code in 2.6.25
-Why:   obsolete OSS drivers
-Who:   Adrian Bunk <bunk@stusta.de>
-
----------------------------
-
 What: libata spindown skipping and warning
 When: Dec 2008
 Why:  Some halt(8) implementations synchronize caches for and spin
index 1de155e2dc3664c0a3932b4b2ba880224a0e2478..e68021c08fbd593d19eeab3e688310c9e919a4e6 100644 (file)
@@ -32,6 +32,8 @@ directory-locking
        - info about the locking scheme used for directory operations.
 dlmfs.txt
        - info on the userspace interface to the OCFS2 DLM.
+dnotify.txt
+       - info about directory notification in Linux.
 ecryptfs.txt
        - docs on eCryptfs: stacked cryptographic filesystem for Linux.
 ext2.txt
@@ -80,6 +82,8 @@ relay.txt
        - info on relay, for efficient streaming from kernel to user space.
 romfs.txt
        - description of the ROMFS filesystem.
+sharedsubtree.txt
+       - a description of shared subtrees for namespaces.
 smbfs.txt
        - info on using filesystems with the SMB protocol (Win 3.11 and NT).
 spufs.txt
index 37c10cba717725f599ec999eb0a0a4ff6b1fc483..42d4b30b10459966c9ea0db1ae111272e0af1482 100644 (file)
@@ -90,7 +90,6 @@ of the locking scheme for directory operations.
 prototypes:
        struct inode *(*alloc_inode)(struct super_block *sb);
        void (*destroy_inode)(struct inode *);
-       void (*read_inode) (struct inode *);
        void (*dirty_inode) (struct inode *);
        int (*write_inode) (struct inode *, int);
        void (*put_inode) (struct inode *);
@@ -114,7 +113,6 @@ locking rules:
                        BKL     s_lock  s_umount
 alloc_inode:           no      no      no
 destroy_inode:         no
-read_inode:            no                              (see below)
 dirty_inode:           no                              (must not sleep)
 write_inode:           no
 put_inode:             no
@@ -133,7 +131,6 @@ show_options:               no                              (vfsmount->sem)
 quota_read:            no      no      no              (see below)
 quota_write:           no      no      no              (see below)
 
-->read_inode() is not a method - it's a callback used in iget().
 ->remount_fs() will have the s_umount lock if it's already mounted.
 When called from get_sb_single, it does NOT have the s_umount lock.
 ->quota_read() and ->quota_write() functions are both guaranteed to
diff --git a/Documentation/filesystems/dnotify.txt b/Documentation/filesystems/dnotify.txt
new file mode 100644 (file)
index 0000000..9f5d338
--- /dev/null
@@ -0,0 +1,99 @@
+               Linux Directory Notification
+               ============================
+
+          Stephen Rothwell <sfr@canb.auug.org.au>
+
+The intention of directory notification is to allow user applications
+to be notified when a directory, or any of the files in it, are changed.
+The basic mechanism involves the application registering for notification
+on a directory using a fcntl(2) call and the notifications themselves
+being delivered using signals.
+
+The application decides which "events" it wants to be notified about.
+The currently defined events are:
+
+       DN_ACCESS       A file in the directory was accessed (read)
+       DN_MODIFY       A file in the directory was modified (write,truncate)
+       DN_CREATE       A file was created in the directory
+       DN_DELETE       A file was unlinked from directory
+       DN_RENAME       A file in the directory was renamed
+       DN_ATTRIB       A file in the directory had its attributes
+                       changed (chmod,chown)
+
+Usually, the application must reregister after each notification, but
+if DN_MULTISHOT is or'ed with the event mask, then the registration will
+remain until explicitly removed (by registering for no events).
+
+By default, SIGIO will be delivered to the process and no other useful
+information.  However, if the F_SETSIG fcntl(2) call is used to let the
+kernel know which signal to deliver, a siginfo structure will be passed to
+the signal handler and the si_fd member of that structure will contain the
+file descriptor associated with the directory in which the event occurred.
+
+Preferably the application will choose one of the real time signals
+(SIGRTMIN + <n>) so that the notifications may be queued.  This is
+especially important if DN_MULTISHOT is specified.  Note that SIGRTMIN
+is often blocked, so it is better to use (at least) SIGRTMIN + 1.
+
+Implementation expectations (features and bugs :-))
+---------------------------
+
+The notification should work for any local access to files even if the
+actual file system is on a remote server.  This implies that remote
+access to files served by local user mode servers should be notified.
+Also, remote accesses to files served by a local kernel NFS server should
+be notified.
+
+In order to make the impact on the file system code as small as possible,
+the problem of hard links to files has been ignored.  So if a file (x)
+exists in two directories (a and b) then a change to the file using the
+name "a/x" should be notified to a program expecting notifications on
+directory "a", but will not be notified to one expecting notifications on
+directory "b".
+
+Also, files that are unlinked, will still cause notifications in the
+last directory that they were linked to.
+
+Configuration
+-------------
+
+Dnotify is controlled via the CONFIG_DNOTIFY configuration option.  When
+disabled, fcntl(fd, F_NOTIFY, ...) will return -EINVAL.
+
+Example
+-------
+
+       #define _GNU_SOURCE     /* needed to get the defines */
+       #include <fcntl.h>      /* in glibc 2.2 this has the needed
+                                          values defined */
+       #include <signal.h>
+       #include <stdio.h>
+       #include <unistd.h>
+
+       static volatile int event_fd;
+
+       static void handler(int sig, siginfo_t *si, void *data)
+       {
+               event_fd = si->si_fd;
+       }
+
+       int main(void)
+       {
+               struct sigaction act;
+               int fd;
+
+               act.sa_sigaction = handler;
+               sigemptyset(&act.sa_mask);
+               act.sa_flags = SA_SIGINFO;
+               sigaction(SIGRTMIN + 1, &act, NULL);
+
+               fd = open(".", O_RDONLY);
+               fcntl(fd, F_SETSIG, SIGRTMIN + 1);
+               fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
+               /* we will now be notified if any of the files
+                  in "." is modified or new files are created */
+               while (1) {
+                       pause();
+                       printf("Got event on fd=%d\n", event_fd);
+               }
+       }
index 0f33c77bc14b2695f6ebb1d70c464bee674c7c33..92b888d540a667c17a630e8dc005cd672c726058 100644 (file)
@@ -34,8 +34,8 @@ FOO_I(inode) (see in-tree filesystems for examples).
 
 Make them ->alloc_inode and ->destroy_inode in your super_operations.
 
-Keep in mind that now you need explicit initialization of private data -
-typically in ->read_inode() and after getting an inode from new_inode().
+Keep in mind that now you need explicit initialization of private data
+typically between calling iget_locked() and unlocking the inode.
 
 At some point that will become mandatory.
 
@@ -173,10 +173,10 @@ should be a non-blocking function that initializes those parts of a
 newly created inode to allow the test function to succeed. 'data' is
 passed as an opaque value to both test and set functions.
 
-When the inode has been created by iget5_locked(), it will be returned with
-the I_NEW flag set and will still be locked. read_inode has not been
-called so the file system still has to finalize the initialization. Once
-the inode is initialized it must be unlocked by calling unlock_new_inode().
+When the inode has been created by iget5_locked(), it will be returned with the
+I_NEW flag set and will still be locked.  The filesystem then needs to finalize
+the initialization. Once the inode is initialized it must be unlocked by
+calling unlock_new_inode().
 
 The filesystem is responsible for setting (and possibly testing) i_ino
 when appropriate. There is also a simpler iget_locked function that
@@ -184,11 +184,19 @@ just takes the superblock and inode number as arguments and does the
 test and set for you.
 
 e.g.
-       inode = iget_locked(sb, ino);
-       if (inode->i_state & I_NEW) {
-               read_inode_from_disk(inode);
-               unlock_new_inode(inode);
-       }
+       inode = iget_locked(sb, ino);
+       if (inode->i_state & I_NEW) {
+               err = read_inode_from_disk(inode);
+               if (err < 0) {
+                       iget_failed(inode);
+                       return err;
+               }
+               unlock_new_inode(inode);
+       }
+
+Note that if the process of setting up a new inode fails, then iget_failed()
+should be called on the inode to render it dead, and an appropriate error
+should be passed back to the caller.
 
 ---
 [recommended]
index e2799b5fafea890153b2d94acb25a712fe6a2587..5681e2fa1496167e6f876b6dab39e9605597a117 100644 (file)
@@ -1029,6 +1029,14 @@ nr_inodes
 Denotes the  number  of  inodes the system has allocated. This number will
 grow and shrink dynamically.
 
+nr_open
+-------
+
+Denotes the maximum number of file-handles a process can
+allocate. Default value is 1024*1024 (1048576) which should be
+enough for most machines. Actual limit depends on RLIMIT_NOFILE
+resource limit.
+
 nr_free_inodes
 --------------
 
diff --git a/Documentation/filesystems/sharedsubtree.txt b/Documentation/filesystems/sharedsubtree.txt
new file mode 100644 (file)
index 0000000..7365400
--- /dev/null
@@ -0,0 +1,1061 @@
+Shared Subtrees
+---------------
+
+Contents:
+       1) Overview
+       2) Features
+       3) smount command
+       4) Use-case
+       5) Detailed semantics
+       6) Quiz
+       7) FAQ
+       8) Implementation
+
+
+1) Overview
+-----------
+
+Consider the following situation:
+
+A process wants to clone its own namespace, but still wants to access the CD
+that got mounted recently.  Shared subtree semantics provide the necessary
+mechanism to accomplish the above.
+
+It provides the necessary building blocks for features like per-user-namespace
+and versioned filesystem.
+
+2) Features
+-----------
+
+Shared subtree provides four different flavors of mounts; struct vfsmount to be
+precise
+
+       a. shared mount
+       b. slave mount
+       c. private mount
+       d. unbindable mount
+
+
+2a) A shared mount can be replicated to as many mountpoints and all the
+replicas continue to be exactly same.
+
+       Here is an example:
+
+       Lets say /mnt has a mount that is shared.
+       mount --make-shared /mnt
+
+       note: mount command does not yet support the --make-shared flag.
+       I have included a small C program which does the same by executing
+       'smount /mnt shared'
+
+       #mount --bind /mnt /tmp
+       The above command replicates the mount at /mnt to the mountpoint /tmp
+       and the contents of both the mounts remain identical.
+
+       #ls /mnt
+       a b c
+
+       #ls /tmp
+       a b c
+
+       Now lets say we mount a device at /tmp/a
+       #mount /dev/sd0  /tmp/a
+
+       #ls /tmp/a
+       t1 t2 t2
+
+       #ls /mnt/a
+       t1 t2 t2
+
+       Note that the mount has propagated to the mount at /mnt as well.
+
+       And the same is true even when /dev/sd0 is mounted on /mnt/a. The
+       contents will be visible under /tmp/a too.
+
+
+2b) A slave mount is like a shared mount except that mount and umount events
+       only propagate towards it.
+
+       All slave mounts have a master mount which is a shared.
+
+       Here is an example:
+
+       Lets say /mnt has a mount which is shared.
+       #mount --make-shared /mnt
+
+       Lets bind mount /mnt to /tmp
+       #mount --bind /mnt /tmp
+
+       the new mount at /tmp becomes a shared mount and it is a replica of
+       the mount at /mnt.
+
+       Now lets make the mount at /tmp; a slave of /mnt
+       #mount --make-slave /tmp
+       [or smount /tmp slave]
+
+       lets mount /dev/sd0 on /mnt/a
+       #mount /dev/sd0 /mnt/a
+
+       #ls /mnt/a
+       t1 t2 t3
+
+       #ls /tmp/a
+       t1 t2 t3
+
+       Note the mount event has propagated to the mount at /tmp
+
+       However lets see what happens if we mount something on the mount at /tmp
+
+       #mount /dev/sd1 /tmp/b
+
+       #ls /tmp/b
+       s1 s2 s3
+
+       #ls /mnt/b
+
+       Note how the mount event has not propagated to the mount at
+       /mnt
+
+
+2c) A private mount does not forward or receive propagation.
+
+       This is the mount we are familiar with. Its the default type.
+
+
+2d) A unbindable mount is a unbindable private mount
+
+       lets say we have a mount at /mnt and we make is unbindable
+
+       #mount --make-unbindable /mnt
+        [ smount /mnt  unbindable ]
+
+        Lets try to bind mount this mount somewhere else.
+        # mount --bind /mnt /tmp
+        mount: wrong fs type, bad option, bad superblock on /mnt,
+               or too many mounted file systems
+
+       Binding a unbindable mount is a invalid operation.
+
+
+3) smount command
+
+       Currently the mount command is not aware of shared subtree features.
+       Work is in progress to add the support in mount ( util-linux package ).
+       Till then use the following program.
+
+       ------------------------------------------------------------------------
+       //
+       //this code was developed my Miklos Szeredi <miklos@szeredi.hu>
+       //and modified by Ram Pai <linuxram@us.ibm.com>
+       // sample usage:
+       //              smount /tmp shared
+       //
+       #include <stdio.h>
+       #include <stdlib.h>
+       #include <unistd.h>
+       #include <string.h>
+       #include <sys/mount.h>
+       #include <sys/fsuid.h>
+
+       #ifndef MS_REC
+       #define MS_REC          0x4000  /* 16384: Recursive loopback */
+       #endif
+
+       #ifndef MS_SHARED
+       #define MS_SHARED               1<<20   /* Shared */
+       #endif
+
+       #ifndef MS_PRIVATE
+       #define MS_PRIVATE              1<<18   /* Private */
+       #endif
+
+       #ifndef MS_SLAVE
+       #define MS_SLAVE                1<<19   /* Slave */
+       #endif
+
+       #ifndef MS_UNBINDABLE
+       #define MS_UNBINDABLE           1<<17   /* Unbindable */
+       #endif
+
+       int main(int argc, char *argv[])
+       {
+               int type;
+               if(argc != 3) {
+                       fprintf(stderr, "usage: %s dir "
+                       "<rshared|rslave|rprivate|runbindable|shared|slave"
+                       "|private|unbindable>\n" , argv[0]);
+                       return 1;
+               }
+
+               fprintf(stdout, "%s %s %s\n", argv[0], argv[1], argv[2]);
+
+               if (strcmp(argv[2],"rshared")==0)
+                       type=(MS_SHARED|MS_REC);
+               else if (strcmp(argv[2],"rslave")==0)
+                       type=(MS_SLAVE|MS_REC);
+               else if (strcmp(argv[2],"rprivate")==0)
+                       type=(MS_PRIVATE|MS_REC);
+               else if (strcmp(argv[2],"runbindable")==0)
+                       type=(MS_UNBINDABLE|MS_REC);
+               else if (strcmp(argv[2],"shared")==0)
+                       type=MS_SHARED;
+               else if (strcmp(argv[2],"slave")==0)
+                       type=MS_SLAVE;
+               else if (strcmp(argv[2],"private")==0)
+                       type=MS_PRIVATE;
+               else if (strcmp(argv[2],"unbindable")==0)
+                       type=MS_UNBINDABLE;
+               else {
+                       fprintf(stderr, "invalid operation: %s\n", argv[2]);
+                       return 1;
+               }
+               setfsuid(getuid());
+
+               if(mount("", argv[1], "dontcare", type, "") == -1) {
+                       perror("mount");
+                       return 1;
+               }
+               return 0;
+       }
+       -----------------------------------------------------------------------
+
+       Copy the above code snippet into smount.c
+       gcc -o smount smount.c
+
+
+       (i) To mark all the mounts under /mnt as shared execute the following
+       command:
+
+               smount /mnt rshared
+               the corresponding syntax planned for mount command is
+               mount --make-rshared /mnt
+
+           just to mark a mount /mnt as shared, execute the following
+           command:
+               smount /mnt shared
+               the corresponding syntax planned for mount command is
+               mount --make-shared /mnt
+
+       (ii) To mark all the shared mounts under /mnt as slave execute the
+       following
+
+            command:
+               smount /mnt rslave
+               the corresponding syntax planned for mount command is
+               mount --make-rslave /mnt
+
+           just to mark a mount /mnt as slave, execute the following
+           command:
+               smount /mnt slave
+               the corresponding syntax planned for mount command is
+               mount --make-slave /mnt
+
+       (iii) To mark all the mounts under /mnt as private execute the
+       following command:
+
+               smount /mnt rprivate
+               the corresponding syntax planned for mount command is
+               mount --make-rprivate /mnt
+
+           just to mark a mount /mnt as private, execute the following
+           command:
+               smount /mnt private
+               the corresponding syntax planned for mount command is
+               mount --make-private /mnt
+
+             NOTE: by default all the mounts are created as private. But if
+             you want to change some shared/slave/unbindable  mount as
+             private at a later point in time, this command can help.
+
+       (iv) To mark all the mounts under /mnt as unbindable execute the
+       following
+
+            command:
+               smount /mnt runbindable
+               the corresponding syntax planned for mount command is
+               mount --make-runbindable /mnt
+
+           just to mark a mount /mnt as unbindable, execute the following
+           command:
+               smount /mnt unbindable
+               the corresponding syntax planned for mount command is
+               mount --make-unbindable /mnt
+
+
+4) Use cases
+------------
+
+       A) A process wants to clone its own namespace, but still wants to
+          access the CD that got mounted recently.
+
+          Solution:
+
+               The system administrator can make the mount at /cdrom shared
+               mount --bind /cdrom /cdrom
+               mount --make-shared /cdrom
+
+               Now any process that clones off a new namespace will have a
+               mount at /cdrom which is a replica of the same mount in the
+               parent namespace.
+
+               So when a CD is inserted and mounted at /cdrom that mount gets
+               propagated to the other mount at /cdrom in all the other clone
+               namespaces.
+
+       B) A process wants its mounts invisible to any other process, but
+       still be able to see the other system mounts.
+
+          Solution:
+
+               To begin with, the administrator can mark the entire mount tree
+               as shareable.
+
+               mount --make-rshared /
+
+               A new process can clone off a new namespace. And mark some part
+               of its namespace as slave
+
+               mount --make-rslave /myprivatetree
+
+               Hence forth any mounts within the /myprivatetree done by the
+               process will not show up in any other namespace. However mounts
+               done in the parent namespace under /myprivatetree still shows
+               up in the process's namespace.
+
+
+       Apart from the above semantics this feature provides the
+       building blocks to solve the following problems:
+
+       C)  Per-user namespace
+
+               The above semantics allows a way to share mounts across
+               namespaces.  But namespaces are associated with processes. If
+               namespaces are made first class objects with user API to
+               associate/disassociate a namespace with userid, then each user
+               could have his/her own namespace and tailor it to his/her
+               requirements. Offcourse its needs support from PAM.
+
+       D)  Versioned files
+
+               If the entire mount tree is visible at multiple locations, then
+               a underlying versioning file system can return different
+               version of the file depending on the path used to access that
+               file.
+
+               An example is:
+
+               mount --make-shared /
+               mount --rbind / /view/v1
+               mount --rbind / /view/v2
+               mount --rbind / /view/v3
+               mount --rbind / /view/v4
+
+               and if /usr has a versioning filesystem mounted, than that
+               mount appears at /view/v1/usr, /view/v2/usr, /view/v3/usr and
+               /view/v4/usr too
+
+               A user can request v3 version of the file /usr/fs/namespace.c
+               by accessing /view/v3/usr/fs/namespace.c . The underlying
+               versioning filesystem can then decipher that v3 version of the
+               filesystem is being requested and return the corresponding
+               inode.
+
+5) Detailed semantics:
+-------------------
+       The section below explains the detailed semantics of
+       bind, rbind, move, mount, umount and clone-namespace operations.
+
+       Note: the word 'vfsmount' and the noun 'mount' have been used
+       to mean the same thing, throughout this document.
+
+5a) Mount states
+
+       A given mount can be in one of the following states
+       1) shared
+       2) slave
+       3) shared and slave
+       4) private
+       5) unbindable
+
+       A 'propagation event' is defined as event generated on a vfsmount
+       that leads to mount or unmount actions in other vfsmounts.
+
+       A 'peer group' is defined as a group of vfsmounts that propagate
+       events to each other.
+
+       (1) Shared mounts
+
+               A 'shared mount' is defined as a vfsmount that belongs to a
+               'peer group'.
+
+               For example:
+                       mount --make-shared /mnt
+                       mount --bin /mnt /tmp
+
+               The mount at /mnt and that at /tmp are both shared and belong
+               to the same peer group. Anything mounted or unmounted under
+               /mnt or /tmp reflect in all the other mounts of its peer
+               group.
+
+
+       (2) Slave mounts
+
+               A 'slave mount' is defined as a vfsmount that receives
+               propagation events and does not forward propagation events.
+
+               A slave mount as the name implies has a master mount from which
+               mount/unmount events are received. Events do not propagate from
+               the slave mount to the master.  Only a shared mount can be made
+               a slave by executing the following command
+
+                       mount --make-slave mount
+
+               A shared mount that is made as a slave is no more shared unless
+               modified to become shared.
+
+       (3) Shared and Slave
+
+               A vfsmount can be both shared as well as slave.  This state
+               indicates that the mount is a slave of some vfsmount, and
+               has its own peer group too.  This vfsmount receives propagation
+               events from its master vfsmount, and also forwards propagation
+               events to its 'peer group' and to its slave vfsmounts.
+
+               Strictly speaking, the vfsmount is shared having its own
+               peer group, and this peer-group is a slave of some other
+               peer group.
+
+               Only a slave vfsmount can be made as 'shared and slave' by
+               either executing the following command
+                       mount --make-shared mount
+               or by moving the slave vfsmount under a shared vfsmount.
+
+       (4) Private mount
+
+               A 'private mount' is defined as vfsmount that does not
+               receive or forward any propagation events.
+
+       (5) Unbindable mount
+
+               A 'unbindable mount' is defined as vfsmount that does not
+               receive or forward any propagation events and cannot
+               be bind mounted.
+
+
+       State diagram:
+       The state diagram below explains the state transition of a mount,
+       in response to various commands.
+       ------------------------------------------------------------------------
+       |             |make-shared |  make-slave  | make-private |make-unbindab|
+       --------------|------------|--------------|--------------|-------------|
+       |shared       |shared      |*slave/private|   private    | unbindable  |
+       |             |            |              |              |             |
+       |-------------|------------|--------------|--------------|-------------|
+       |slave        |shared      |    **slave   |    private   | unbindable  |
+       |             |and slave   |              |              |             |
+       |-------------|------------|--------------|--------------|-------------|
+       |shared       |shared      |    slave     |    private   | unbindable  |
+       |and slave    |and slave   |              |              |             |
+       |-------------|------------|--------------|--------------|-------------|
+       |private      |shared      |  **private   |    private   | unbindable  |
+       |-------------|------------|--------------|--------------|-------------|
+       |unbindable   |shared      |**unbindable  |    private   | unbindable  |
+       ------------------------------------------------------------------------
+
+       * if the shared mount is the only mount in its peer group, making it
+       slave, makes it private automatically. Note that there is no master to
+       which it can be slaved to.
+
+       ** slaving a non-shared mount has no effect on the mount.
+
+       Apart from the commands listed below, the 'move' operation also changes
+       the state of a mount depending on type of the destination mount. Its
+       explained in section 5d.
+
+5b) Bind semantics
+
+       Consider the following command
+
+       mount --bind A/a  B/b
+
+       where 'A' is the source mount, 'a' is the dentry in the mount 'A', 'B'
+       is the destination mount and 'b' is the dentry in the destination mount.
+
+       The outcome depends on the type of mount of 'A' and 'B'. The table
+       below contains quick reference.
+   ---------------------------------------------------------------------------
+   |         BIND MOUNT OPERATION                                            |
+   |**************************************************************************
+   |source(A)->| shared       |       private  |       slave    | unbindable |
+   | dest(B)  |               |                |                |            |
+   |   |      |               |                |                |            |
+   |   v      |               |                |                |            |
+   |**************************************************************************
+   |  shared  | shared        |     shared     | shared & slave |  invalid   |
+   |          |               |                |                |            |
+   |non-shared| shared        |      private   |      slave     |  invalid   |
+   ***************************************************************************
+
+       Details:
+
+       1. 'A' is a shared mount and 'B' is a shared mount. A new mount 'C'
+       which is clone of 'A', is created. Its root dentry is 'a' . 'C' is
+       mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ...
+       are created and mounted at the dentry 'b' on all mounts where 'B'
+       propagates to. A new propagation tree containing 'C1',..,'Cn' is
+       created. This propagation tree is identical to the propagation tree of
+       'B'.  And finally the peer-group of 'C' is merged with the peer group
+       of 'A'.
+
+       2. 'A' is a private mount and 'B' is a shared mount. A new mount 'C'
+       which is clone of 'A', is created. Its root dentry is 'a'. 'C' is
+       mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ...
+       are created and mounted at the dentry 'b' on all mounts where 'B'
+       propagates to. A new propagation tree is set containing all new mounts
+       'C', 'C1', .., 'Cn' with exactly the same configuration as the
+       propagation tree for 'B'.
+
+       3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount. A new
+       mount 'C' which is clone of 'A', is created. Its root dentry is 'a' .
+       'C' is mounted on mount 'B' at dentry 'b'. Also new mounts 'C1', 'C2',
+       'C3' ... are created and mounted at the dentry 'b' on all mounts where
+       'B' propagates to. A new propagation tree containing the new mounts
+       'C','C1',..  'Cn' is created. This propagation tree is identical to the
+       propagation tree for 'B'. And finally the mount 'C' and its peer group
+       is made the slave of mount 'Z'.  In other words, mount 'C' is in the
+       state 'slave and shared'.
+
+       4. 'A' is a unbindable mount and 'B' is a shared mount. This is a
+       invalid operation.
+
+       5. 'A' is a private mount and 'B' is a non-shared(private or slave or
+       unbindable) mount. A new mount 'C' which is clone of 'A', is created.
+       Its root dentry is 'a'. 'C' is mounted on mount 'B' at dentry 'b'.
+
+       6. 'A' is a shared mount and 'B' is a non-shared mount. A new mount 'C'
+       which is a clone of 'A' is created. Its root dentry is 'a'. 'C' is
+       mounted on mount 'B' at dentry 'b'.  'C' is made a member of the
+       peer-group of 'A'.
+
+       7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount. A
+       new mount 'C' which is a clone of 'A' is created. Its root dentry is
+       'a'.  'C' is mounted on mount 'B' at dentry 'b'. Also 'C' is set as a
+       slave mount of 'Z'. In other words 'A' and 'C' are both slave mounts of
+       'Z'.  All mount/unmount events on 'Z' propagates to 'A' and 'C'. But
+       mount/unmount on 'A' do not propagate anywhere else. Similarly
+       mount/unmount on 'C' do not propagate anywhere else.
+
+       8. 'A' is a unbindable mount and 'B' is a non-shared mount. This is a
+       invalid operation. A unbindable mount cannot be bind mounted.
+
+5c) Rbind semantics
+
+       rbind is same as bind. Bind replicates the specified mount.  Rbind
+       replicates all the mounts in the tree belonging to the specified mount.
+       Rbind mount is bind mount applied to all the mounts in the tree.
+
+       If the source tree that is rbind has some unbindable mounts,
+       then the subtree under the unbindable mount is pruned in the new
+       location.
+
+       eg: lets say we have the following mount tree.
+
+               A
+             /   \
+             B   C
+            / \ / \
+            D E F G
+
+            Lets say all the mount except the mount C in the tree are
+            of a type other than unbindable.
+
+            If this tree is rbound to say Z
+
+            We will have the following tree at the new location.
+
+               Z
+               |
+               A'
+              /
+             B'                Note how the tree under C is pruned
+            / \                in the new location.
+           D' E'
+
+
+
+5d) Move semantics
+
+       Consider the following command
+
+       mount --move A  B/b
+
+       where 'A' is the source mount, 'B' is the destination mount and 'b' is
+       the dentry in the destination mount.
+
+       The outcome depends on the type of the mount of 'A' and 'B'. The table
+       below is a quick reference.
+   ---------------------------------------------------------------------------
+   |                   MOVE MOUNT OPERATION                                 |
+   |**************************************************************************
+   | source(A)->| shared      |       private  |       slave    | unbindable |
+   | dest(B)  |               |                |                |            |
+   |   |      |               |                |                |            |
+   |   v      |               |                |                |            |
+   |**************************************************************************
+   |  shared  | shared        |     shared     |shared and slave|  invalid   |
+   |          |               |                |                |            |
+   |non-shared| shared        |      private   |    slave       | unbindable |
+   ***************************************************************************
+       NOTE: moving a mount residing under a shared mount is invalid.
+
+      Details follow:
+
+       1. 'A' is a shared mount and 'B' is a shared mount.  The mount 'A' is
+       mounted on mount 'B' at dentry 'b'.  Also new mounts 'A1', 'A2'...'An'
+       are created and mounted at dentry 'b' on all mounts that receive
+       propagation from mount 'B'. A new propagation tree is created in the
+       exact same configuration as that of 'B'. This new propagation tree
+       contains all the new mounts 'A1', 'A2'...  'An'.  And this new
+       propagation tree is appended to the already existing propagation tree
+       of 'A'.
+
+       2. 'A' is a private mount and 'B' is a shared mount. The mount 'A' is
+       mounted on mount 'B' at dentry 'b'. Also new mount 'A1', 'A2'... 'An'
+       are created and mounted at dentry 'b' on all mounts that receive
+       propagation from mount 'B'. The mount 'A' becomes a shared mount and a
+       propagation tree is created which is identical to that of
+       'B'. This new propagation tree contains all the new mounts 'A1',
+       'A2'...  'An'.
+
+       3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount.  The
+       mount 'A' is mounted on mount 'B' at dentry 'b'.  Also new mounts 'A1',
+       'A2'... 'An' are created and mounted at dentry 'b' on all mounts that
+       receive propagation from mount 'B'. A new propagation tree is created
+       in the exact same configuration as that of 'B'. This new propagation
+       tree contains all the new mounts 'A1', 'A2'...  'An'.  And this new
+       propagation tree is appended to the already existing propagation tree of
+       'A'.  Mount 'A' continues to be the slave mount of 'Z' but it also
+       becomes 'shared'.
+
+       4. 'A' is a unbindable mount and 'B' is a shared mount. The operation
+       is invalid. Because mounting anything on the shared mount 'B' can
+       create new mounts that get mounted on the mounts that receive
+       propagation from 'B'.  And since the mount 'A' is unbindable, cloning
+       it to mount at other mountpoints is not possible.
+
+       5. 'A' is a private mount and 'B' is a non-shared(private or slave or
+       unbindable) mount. The mount 'A' is mounted on mount 'B' at dentry 'b'.
+
+       6. 'A' is a shared mount and 'B' is a non-shared mount.  The mount 'A'
+       is mounted on mount 'B' at dentry 'b'.  Mount 'A' continues to be a
+       shared mount.
+
+       7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount.
+       The mount 'A' is mounted on mount 'B' at dentry 'b'.  Mount 'A'
+       continues to be a slave mount of mount 'Z'.
+
+       8. 'A' is a unbindable mount and 'B' is a non-shared mount. The mount
+       'A' is mounted on mount 'B' at dentry 'b'. Mount 'A' continues to be a
+       unbindable mount.
+
+5e) Mount semantics
+
+       Consider the following command
+
+       mount device  B/b
+
+       'B' is the destination mount and 'b' is the dentry in the destination
+       mount.
+
+       The above operation is the same as bind operation with the exception
+       that the source mount is always a private mount.
+
+
+5f) Unmount semantics
+
+       Consider the following command
+
+       umount A
+
+       where 'A' is a mount mounted on mount 'B' at dentry 'b'.
+
+       If mount 'B' is shared, then all most-recently-mounted mounts at dentry
+       'b' on mounts that receive propagation from mount 'B' and does not have
+       sub-mounts within them are unmounted.
+
+       Example: Lets say 'B1', 'B2', 'B3' are shared mounts that propagate to
+       each other.
+
+       lets say 'A1', 'A2', 'A3' are first mounted at dentry 'b' on mount
+       'B1', 'B2' and 'B3' respectively.
+
+       lets say 'C1', 'C2', 'C3' are next mounted at the same dentry 'b' on
+       mount 'B1', 'B2' and 'B3' respectively.
+
+       if 'C1' is unmounted, all the mounts that are most-recently-mounted on
+       'B1' and on the mounts that 'B1' propagates-to are unmounted.
+
+       'B1' propagates to 'B2' and 'B3'. And the most recently mounted mount
+       on 'B2' at dentry 'b' is 'C2', and that of mount 'B3' is 'C3'.
+
+       So all 'C1', 'C2' and 'C3' should be unmounted.
+
+       If any of 'C2' or 'C3' has some child mounts, then that mount is not
+       unmounted, but all other mounts are unmounted. However if 'C1' is told
+       to be unmounted and 'C1' has some sub-mounts, the umount operation is
+       failed entirely.
+
+5g) Clone Namespace
+
+       A cloned namespace contains all the mounts as that of the parent
+       namespace.
+
+       Lets say 'A' and 'B' are the corresponding mounts in the parent and the
+       child namespace.
+
+       If 'A' is shared, then 'B' is also shared and 'A' and 'B' propagate to
+       each other.
+
+       If 'A' is a slave mount of 'Z', then 'B' is also the slave mount of
+       'Z'.
+
+       If 'A' is a private mount, then 'B' is a private mount too.
+
+       If 'A' is unbindable mount, then 'B' is a unbindable mount too.
+
+
+6) Quiz
+
+       A. What is the result of the following command sequence?
+
+               mount --bind /mnt /mnt
+               mount --make-shared /mnt
+               mount --bind /mnt /tmp
+               mount --move /tmp /mnt/1
+
+               what should be the contents of /mnt /mnt/1 /mnt/1/1 should be?
+               Should they all be identical? or should /mnt and /mnt/1 be
+               identical only?
+
+
+       B. What is the result of the following command sequence?
+
+               mount --make-rshared /
+               mkdir -p /v/1
+               mount --rbind / /v/1
+
+               what should be the content of /v/1/v/1 be?
+
+
+       C. What is the result of the following command sequence?
+
+               mount --bind /mnt /mnt
+               mount --make-shared /mnt
+               mkdir -p /mnt/1/2/3 /mnt/1/test
+               mount --bind /mnt/1 /tmp
+               mount --make-slave /mnt
+               mount --make-shared /mnt
+               mount --bind /mnt/1/2 /tmp1
+               mount --make-slave /mnt
+
+               At this point we have the first mount at /tmp and
+               its root dentry is 1. Lets call this mount 'A'
+               And then we have a second mount at /tmp1 with root
+               dentry 2. Lets call this mount 'B'
+               Next we have a third mount at /mnt with root dentry
+               mnt. Lets call this mount 'C'
+
+               'B' is the slave of 'A' and 'C' is a slave of 'B'
+               A -> B -> C
+
+               at this point if we execute the following command
+
+               mount --bind /bin /tmp/test
+
+               The mount is attempted on 'A'
+
+               will the mount propagate to 'B' and 'C' ?
+
+               what would be the contents of
+               /mnt/1/test be?
+
+7) FAQ
+
+       Q1. Why is bind mount needed? How is it different from symbolic links?
+               symbolic links can get stale if the destination mount gets
+               unmounted or moved. Bind mounts continue to exist even if the
+               other mount is unmounted or moved.
+
+       Q2. Why can't the shared subtree be implemented using exportfs?
+
+               exportfs is a heavyweight way of accomplishing part of what
+               shared subtree can do. I cannot imagine a way to implement the
+               semantics of slave mount using exportfs?
+
+       Q3 Why is unbindable mount needed?
+
+               Lets say we want to replicate the mount tree at multiple
+               locations within the same subtree.
+
+               if one rbind mounts a tree within the same subtree 'n' times
+               the number of mounts created is an exponential function of 'n'.
+               Having unbindable mount can help prune the unneeded bind
+               mounts. Here is a example.
+
+               step 1:
+                  lets say the root tree has just two directories with
+                  one vfsmount.
+                                   root
+                                  /    \
+                                 tmp    usr
+
+                   And we want to replicate the tree at multiple
+                   mountpoints under /root/tmp
+
+               step2:
+                     mount --make-shared /root
+
+                     mkdir -p /tmp/m1
+
+                     mount --rbind /root /tmp/m1
+
+                     the new tree now looks like this:
+
+                                   root
+                                  /    \
+                                tmp    usr
+                               /
+                              m1
+                             /  \
+                            tmp  usr
+                            /
+                           m1
+
+                         it has two vfsmounts
+
+               step3:
+                           mkdir -p /tmp/m2
+                           mount --rbind /root /tmp/m2
+
+                       the new tree now looks like this:
+
+                                     root
+                                    /    \
+                                  tmp     usr
+                                 /    \
+                               m1       m2
+                              / \       /  \
+                            tmp  usr   tmp  usr
+                            / \          /
+                           m1  m2      m1
+                               / \     /  \
+                             tmp usr  tmp   usr
+                             /        / \
+                            m1       m1  m2
+                           /  \
+                         tmp   usr
+                         /  \
+                        m1   m2
+
+                      it has 6 vfsmounts
+
+               step 4:
+                         mkdir -p /tmp/m3
+                         mount --rbind /root /tmp/m3
+
+                         I wont' draw the tree..but it has 24 vfsmounts
+
+
+               at step i the number of vfsmounts is V[i] = i*V[i-1].
+               This is an exponential function. And this tree has way more
+               mounts than what we really needed in the first place.
+
+               One could use a series of umount at each step to prune
+               out the unneeded mounts. But there is a better solution.
+               Unclonable mounts come in handy here.
+
+               step 1:
+                  lets say the root tree has just two directories with
+                  one vfsmount.
+                                   root
+                                  /    \
+                                 tmp    usr
+
+                   How do we set up the same tree at multiple locations under
+                   /root/tmp
+
+               step2:
+                     mount --bind /root/tmp /root/tmp
+
+                     mount --make-rshared /root
+                     mount --make-unbindable /root/tmp
+
+                     mkdir -p /tmp/m1
+
+                     mount --rbind /root /tmp/m1
+
+                     the new tree now looks like this:
+
+                                   root
+                                  /    \
+                                tmp    usr
+                               /
+                              m1
+                             /  \
+                            tmp  usr
+
+               step3:
+                           mkdir -p /tmp/m2
+                           mount --rbind /root /tmp/m2
+
+                     the new tree now looks like this:
+
+                                   root
+                                  /    \
+                                tmp    usr
+                               /   \
+                              m1     m2
+                             /  \     / \
+                            tmp  usr tmp usr
+
+               step4:
+
+                           mkdir -p /tmp/m3
+                           mount --rbind /root /tmp/m3
+
+                     the new tree now looks like this:
+
+                                         root
+                                     /           \
+                                    tmp           usr
+                                /    \    \
+                              m1     m2     m3
+                             /  \     / \    /  \
+                            tmp  usr tmp usr tmp usr
+
+8) Implementation
+
+8A) Datastructure
+
+       4 new fields are introduced to struct vfsmount
+       ->mnt_share
+       ->mnt_slave_list
+       ->mnt_slave
+       ->mnt_master
+
+       ->mnt_share links together all the mount to/from which this vfsmount
+               send/receives propagation events.
+
+       ->mnt_slave_list links all the mounts to which this vfsmount propagates
+               to.
+
+       ->mnt_slave links together all the slaves that its master vfsmount
+               propagates to.
+
+       ->mnt_master points to the master vfsmount from which this vfsmount
+               receives propagation.
+
+       ->mnt_flags takes two more flags to indicate the propagation status of
+               the vfsmount.  MNT_SHARE indicates that the vfsmount is a shared
+               vfsmount.  MNT_UNCLONABLE indicates that the vfsmount cannot be
+               replicated.
+
+       All the shared vfsmounts in a peer group form a cyclic list through
+       ->mnt_share.
+
+       All vfsmounts with the same ->mnt_master form on a cyclic list anchored
+       in ->mnt_master->mnt_slave_list and going through ->mnt_slave.
+
+        ->mnt_master can point to arbitrary (and possibly different) members
+        of master peer group.  To find all immediate slaves of a peer group
+        you need to go through _all_ ->mnt_slave_list of its members.
+        Conceptually it's just a single set - distribution among the
+        individual lists does not affect propagation or the way propagation
+        tree is modified by operations.
+
+       A example propagation tree looks as shown in the figure below.
+       [ NOTE: Though it looks like a forest, if we consider all the shared
+       mounts as a conceptual entity called 'pnode', it becomes a tree]
+
+
+                       A <--> B <--> C <---> D
+                      /|\            /|      |\
+                     / F G          J K      H I
+                    /
+                   E<-->K
+                       /|\
+                      M L N
+
+       In the above figure  A,B,C and D all are shared and propagate to each
+       other.   'A' has got 3 slave mounts 'E' 'F' and 'G' 'C' has got 2 slave
+       mounts 'J' and 'K'  and  'D' has got two slave mounts 'H' and 'I'.
+       'E' is also shared with 'K' and they propagate to each other.  And
+       'K' has 3 slaves 'M', 'L' and 'N'
+
+       A's ->mnt_share links with the ->mnt_share of 'B' 'C' and 'D'
+
+       A's ->mnt_slave_list links with ->mnt_slave of 'E', 'K', 'F' and 'G'
+
+       E's ->mnt_share links with ->mnt_share of K
+       'E', 'K', 'F', 'G' have their ->mnt_master point to struct
+                               vfsmount of 'A'
+       'M', 'L', 'N' have their ->mnt_master point to struct vfsmount of 'K'
+       K's ->mnt_slave_list links with ->mnt_slave of 'M', 'L' and 'N'
+
+       C's ->mnt_slave_list links with ->mnt_slave of 'J' and 'K'
+       J and K's ->mnt_master points to struct vfsmount of C
+       and finally D's ->mnt_slave_list links with ->mnt_slave of 'H' and 'I'
+       'H' and 'I' have their ->mnt_master pointing to struct vfsmount of 'D'.
+
+
+       NOTE: The propagation tree is orthogonal to the mount tree.
+
+
+8B Algorithm:
+
+       The crux of the implementation resides in rbind/move operation.
+
+       The overall algorithm breaks the operation into 3 phases: (look at
+       attach_recursive_mnt() and propagate_mnt())
+
+       1. prepare phase.
+       2. commit phases.
+       3. abort phases.
+
+       Prepare phase:
+
+       for each mount in the source tree:
+                  a) Create the necessary number of mount trees to
+                       be attached to each of the mounts that receive
+                       propagation from the destination mount.
+                  b) Do not attach any of the trees to its destination.
+                     However note down its ->mnt_parent and ->mnt_mountpoint
+                  c) Link all the new mounts to form a propagation tree that
+                     is identical to the propagation tree of the destination
+                     mount.
+
+                  If this phase is successful, there should be 'n' new
+                  propagation trees; where 'n' is the number of mounts in the
+                  source tree.  Go to the commit phase
+
+                  Also there should be 'm' new mount trees, where 'm' is
+                  the number of mounts to which the destination mount
+                  propagates to.
+
+                  if any memory allocations fail, go to the abort phase.
+
+       Commit phase
+               attach each of the mount trees to their corresponding
+               destination mounts.
+
+       Abort phase
+               delete all the newly created trees.
+
+       NOTE: all the propagation related functionality resides in the file
+       pnode.c
+
+
+------------------------------------------------------------------------
+
+version 0.1  (created the initial document, Ram Pai linuxram@us.ibm.com)
+version 0.2  (Incorporated comments from Al Viro)
index 9d019d35728f28bcb9ecfeaf5bd3a4227f026586..bd55038b56f5464df637c618abe0a06318f39e72 100644 (file)
@@ -203,8 +203,6 @@ struct super_operations {
         struct inode *(*alloc_inode)(struct super_block *sb);
         void (*destroy_inode)(struct inode *);
 
-        void (*read_inode) (struct inode *);
-
         void (*dirty_inode) (struct inode *);
         int (*write_inode) (struct inode *, int);
         void (*put_inode) (struct inode *);
@@ -242,15 +240,6 @@ or bottom half).
        ->alloc_inode was defined and simply undoes anything done by
        ->alloc_inode.
 
-  read_inode: this method is called to read a specific inode from the
-        mounted filesystem.  The i_ino member in the struct inode is
-       initialized by the VFS to indicate which inode to read. Other
-       members are filled in by this method.
-
-       You can set this to NULL and use iget5_locked() instead of iget()
-       to read inodes.  This is necessary for filesystems for which the
-       inode number is not sufficient to identify an inode.
-
   dirty_inode: this method is called by the VFS to mark an inode dirty.
 
   write_inode: this method is called when the VFS needs to write an
@@ -308,9 +297,9 @@ or bottom half).
 
   quota_write: called by the VFS to write to filesystem quota file.
 
-The read_inode() method is responsible for filling in the "i_op"
-field. This is a pointer to a "struct inode_operations" which
-describes the methods that can be performed on individual inodes.
+Whoever sets up the inode is responsible for filling in the "i_op" field. This
+is a pointer to a "struct inode_operations" which describes the methods that
+can be performed on individual inodes.
 
 
 The Inode Object
index 53a63890aea49a9def4240e426ddce1db32439c8..30c101761d0d54f532122e8a804d376de2aa61d8 100644 (file)
@@ -96,7 +96,9 @@ or in registers (e.g., for x86_64 or for an i386 fastcall function).
 The jprobe will work in either case, so long as the handler's
 prototype matches that of the probed function.
 
-1.3 How Does a Return Probe Work?
+1.3 Return Probes
+
+1.3.1 How Does a Return Probe Work?
 
 When you call register_kretprobe(), Kprobes establishes a kprobe at
 the entry to the function.  When the probed function is called and this
@@ -107,9 +109,9 @@ At boot time, Kprobes registers a kprobe at the trampoline.
 
 When the probed function executes its return instruction, control
 passes to the trampoline and that probe is hit.  Kprobes' trampoline
-handler calls the user-specified handler associated with the kretprobe,
-then sets the saved instruction pointer to the saved return address,
-and that's where execution resumes upon return from the trap.
+handler calls the user-specified return handler associated with the
+kretprobe, then sets the saved instruction pointer to the saved return
+address, and that's where execution resumes upon return from the trap.
 
 While the probed function is executing, its return address is
 stored in an object of type kretprobe_instance.  Before calling
@@ -131,6 +133,30 @@ zero when the return probe is registered, and is incremented every
 time the probed function is entered but there is no kretprobe_instance
 object available for establishing the return probe.
 
+1.3.2 Kretprobe entry-handler
+
+Kretprobes also provides an optional user-specified handler which runs
+on function entry. This handler is specified by setting the entry_handler
+field of the kretprobe struct. Whenever the kprobe placed by kretprobe at the
+function entry is hit, the user-defined entry_handler, if any, is invoked.
+If the entry_handler returns 0 (success) then a corresponding return handler
+is guaranteed to be called upon function return. If the entry_handler
+returns a non-zero error then Kprobes leaves the return address as is, and
+the kretprobe has no further effect for that particular function instance.
+
+Multiple entry and return handler invocations are matched using the unique
+kretprobe_instance object associated with them. Additionally, a user
+may also specify per return-instance private data to be part of each
+kretprobe_instance object. This is especially useful when sharing private
+data between corresponding user entry and return handlers. The size of each
+private data object can be specified at kretprobe registration time by
+setting the data_size field of the kretprobe struct. This data can be
+accessed through the data field of each kretprobe_instance object.
+
+In case probed function is entered but there is no kretprobe_instance
+object available, then in addition to incrementing the nmissed count,
+the user entry_handler invocation is also skipped.
+
 2. Architectures Supported
 
 Kprobes, jprobes, and return probes are implemented on the following
@@ -274,6 +300,8 @@ of interest:
 - ret_addr: the return address
 - rp: points to the corresponding kretprobe object
 - task: points to the corresponding task struct
+- data: points to per return-instance private data; see "Kretprobe
+       entry-handler" for details.
 
 The regs_return_value(regs) macro provides a simple abstraction to
 extract the return value from the appropriate register as defined by
@@ -556,23 +584,52 @@ report failed calls to sys_open().
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/kprobes.h>
+#include <linux/ktime.h>
+
+/* per-instance private data */
+struct my_data {
+       ktime_t entry_stamp;
+};
 
 static const char *probed_func = "sys_open";
 
-/* Return-probe handler: If the probed function fails, log the return value. */
-static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+/* Timestamp function entry. */
+static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct my_data *data;
+
+       if(!current->mm)
+               return 1; /* skip kernel threads */
+
+       data = (struct my_data *)ri->data;
+       data->entry_stamp = ktime_get();
+       return 0;
+}
+
+/* If the probed function failed, log the return value and duration.
+ * Duration may turn out to be zero consistently, depending upon the
+ * granularity of time accounting on the platform. */
+static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        int retval = regs_return_value(regs);
+       struct my_data *data = (struct my_data *)ri->data;
+       s64 delta;
+       ktime_t now;
+
        if (retval < 0) {
-               printk("%s returns %d\n", probed_func, retval);
+               now = ktime_get();
+               delta = ktime_to_ns(ktime_sub(now, data->entry_stamp));
+               printk("%s: return val = %d (duration = %lld ns)\n",
+                      probed_func, retval, delta);
        }
        return 0;
 }
 
 static struct kretprobe my_kretprobe = {
-       .handler = ret_handler,
-       /* Probe up to 20 instances concurrently. */
-       .maxactive = 20
+       .handler = return_handler,
+       .entry_handler = entry_handler,
+       .data_size = sizeof(struct my_data),
+       .maxactive = 20, /* probe up to 20 instances concurrently */
 };
 
 static int __init kretprobe_init(void)
@@ -584,7 +641,7 @@ static int __init kretprobe_init(void)
                printk("register_kretprobe failed, returned %d\n", ret);
                return -1;
        }
-       printk("Planted return probe at %p\n", my_kretprobe.kp.addr);
+       printk("Kretprobe active on %s\n", my_kretprobe.kp.symbol_name);
        return 0;
 }
 
@@ -594,7 +651,7 @@ static void __exit kretprobe_exit(void)
        printk("kretprobe unregistered\n");
        /* nmissed > 0 suggests that maxactive was set too low. */
        printk("Missed probing %d instances of %s\n",
-               my_kretprobe.nmissed, probed_func);
+              my_kretprobe.nmissed, probed_func);
 }
 
 module_init(kretprobe_init)
index f38b59d00c63a1a635983eaee2278c40b6f744a6..130b6e87aa7ed04af9d3504acecfd7dc0e07ccfc 100644 (file)
@@ -141,10 +141,10 @@ The last rule (rule 3) is the nastiest one to handle.  Say, for
 instance, you have a list of items that are each kref-ed, and you wish
 to get the first one.  You can't just pull the first item off the list
 and kref_get() it.  That violates rule 3 because you are not already
-holding a valid pointer.  You must add locks or semaphores.  For
-instance:
+holding a valid pointer.  You must add a mutex (or some other lock).
+For instance:
 
-static DECLARE_MUTEX(sem);
+static DEFINE_MUTEX(mutex);
 static LIST_HEAD(q);
 struct my_data
 {
@@ -155,12 +155,12 @@ struct my_data
 static struct my_data *get_entry()
 {
        struct my_data *entry = NULL;
-       down(&sem);
+       mutex_lock(&mutex);
        if (!list_empty(&q)) {
                entry = container_of(q.next, struct my_q_entry, link);
                kref_get(&entry->refcount);
        }
-       up(&sem);
+       mutex_unlock(&mutex);
        return entry;
 }
 
@@ -174,9 +174,9 @@ static void release_entry(struct kref *ref)
 
 static void put_entry(struct my_data *entry)
 {
-       down(&sem);
+       mutex_lock(&mutex);
        kref_put(&entry->refcount, release_entry);
-       up(&sem);
+       mutex_unlock(&mutex);
 }
 
 The kref_put() return value is useful if you do not want to hold the
@@ -191,13 +191,13 @@ static void release_entry(struct kref *ref)
 
 static void put_entry(struct my_data *entry)
 {
-       down(&sem);
+       mutex_lock(&mutex);
        if (kref_put(&entry->refcount, release_entry)) {
                list_del(&entry->link);
-               up(&sem);
+               mutex_unlock(&mutex);
                kfree(entry);
        } else
-               up(&sem);
+               mutex_unlock(&mutex);
 }
 
 This is really more useful if you have to call other routines as part
index 5818628207b5ec8b5f32ed6d727857f5f6dcbbec..396cdd982c26505ee39a577a64a7fb2c7472985e 100644 (file)
@@ -416,6 +416,16 @@ also have
      sectors in total that could need to be processed.  The two
      numbers are separated by a '/'  thus effectively showing one
      value, a fraction of the process that is complete.
+     A 'select' on this attribute will return when resync completes,
+     when it reaches the current sync_max (below) and possibly at
+     other times.
+
+   sync_max
+     This is a number of sectors at which point a resync/recovery
+     process will pause.  When a resync is active, the value can
+     only ever be increased, never decreased.  The value of 'max'
+     effectively disables the limit.
+
 
    sync_speed
      This shows the current actual speed, in K/sec, of the current
index e20b19c1b60da04b95cfc62a0cec57428a53bb12..8deffcd68cb8d3fc2737279e780a28bee3726f57 100644 (file)
@@ -182,8 +182,8 @@ driver returns ENOIOCTLCMD.  Some common examples:
        since the frequency is stored in the irq_freq member of the rtc_device
        structure.  Your driver needs to initialize the irq_freq member during
        init.  Make sure you check the requested frequency is in range of your
-       hardware in the irq_set_freq function.  If you cannot actually change
-       the frequency, just return -ENOTTY.
+       hardware in the irq_set_freq function.  If it isn't, return -EINVAL.  If
+       you cannot actually change the frequency, do not define irq_set_freq.
 
 If all else fails, check out the rtc-test.c driver!
 
@@ -268,8 +268,8 @@ int main(int argc, char **argv)
                /* This read will block */
                retval = read(fd, &data, sizeof(unsigned long));
                if (retval == -1) {
-                       perror("read");
-                       exit(errno);
+                       perror("read");
+                       exit(errno);
                }
                fprintf(stderr, " %d",i);
                fflush(stderr);
@@ -326,11 +326,11 @@ test_READ:
                rtc_tm.tm_sec %= 60;
                rtc_tm.tm_min++;
        }
-       if  (rtc_tm.tm_min == 60) {
+       if (rtc_tm.tm_min == 60) {
                rtc_tm.tm_min = 0;
                rtc_tm.tm_hour++;
        }
-       if  (rtc_tm.tm_hour == 24)
+       if (rtc_tm.tm_hour == 24)
                rtc_tm.tm_hour = 0;
 
        retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
@@ -407,8 +407,8 @@ test_PIE:
                                        "\n...Periodic IRQ rate is fixed\n");
                                goto done;
                        }
-                       perror("RTC_IRQP_SET ioctl");
-                       exit(errno);
+                       perror("RTC_IRQP_SET ioctl");
+                       exit(errno);
                }
 
                fprintf(stderr, "\n%ldHz:\t", tmp);
@@ -417,27 +417,27 @@ test_PIE:
                /* Enable periodic interrupts */
                retval = ioctl(fd, RTC_PIE_ON, 0);
                if (retval == -1) {
-                       perror("RTC_PIE_ON ioctl");
-                       exit(errno);
+                       perror("RTC_PIE_ON ioctl");
+                       exit(errno);
                }
 
                for (i=1; i<21; i++) {
-                       /* This blocks */
-                       retval = read(fd, &data, sizeof(unsigned long));
-                       if (retval == -1) {
-                                      perror("read");
-                                      exit(errno);
-                       }
-                       fprintf(stderr, " %d",i);
-                       fflush(stderr);
-                       irqcount++;
+                       /* This blocks */
+                       retval = read(fd, &data, sizeof(unsigned long));
+                       if (retval == -1) {
+                               perror("read");
+                               exit(errno);
+                       }
+                       fprintf(stderr, " %d",i);
+                       fflush(stderr);
+                       irqcount++;
                }
 
                /* Disable periodic interrupts */
                retval = ioctl(fd, RTC_PIE_OFF, 0);
                if (retval == -1) {
-                       perror("RTC_PIE_OFF ioctl");
-                       exit(errno);
+                       perror("RTC_PIE_OFF ioctl");
+                       exit(errno);
                }
        }
 
diff --git a/Documentation/sched-arch.txt b/Documentation/sched-arch.txt
deleted file mode 100644 (file)
index 941615a..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-       CPU Scheduler implementation hints for architecture specific code
-
-       Nick Piggin, 2005
-
-Context switch
-==============
-1. Runqueue locking
-By default, the switch_to arch function is called with the runqueue
-locked. This is usually not a problem unless switch_to may need to
-take the runqueue lock. This is usually due to a wake up operation in
-the context switch. See include/asm-ia64/system.h for an example.
-
-To request the scheduler call switch_to with the runqueue unlocked,
-you must `#define __ARCH_WANT_UNLOCKED_CTXSW` in a header file
-(typically the one where switch_to is defined).
-
-Unlocked context switches introduce only a very minor performance
-penalty to the core scheduler implementation in the CONFIG_SMP case.
-
-2. Interrupt status
-By default, the switch_to arch function is called with interrupts
-disabled. Interrupts may be enabled over the call if it is likely to
-introduce a significant interrupt latency by adding the line
-`#define __ARCH_WANT_INTERRUPTS_ON_CTXSW` in the same place as for
-unlocked context switches. This define also implies
-`__ARCH_WANT_UNLOCKED_CTXSW`. See include/asm-arm/system.h for an
-example.
-
-
-CPU idle
-========
-Your cpu_idle routines need to obey the following rules:
-
-1. Preempt should now disabled over idle routines. Should only
-   be enabled to call schedule() then disabled again.
-
-2. need_resched/TIF_NEED_RESCHED is only ever set, and will never
-   be cleared until the running task has called schedule(). Idle
-   threads need only ever query need_resched, and may never set or
-   clear it.
-
-3. When cpu_idle finds (need_resched() == 'true'), it should call
-   schedule(). It should not call schedule() otherwise.
-
-4. The only time interrupts need to be disabled when checking
-   need_resched is if we are about to sleep the processor until
-   the next interrupt (this doesn't provide any protection of
-   need_resched, it prevents losing an interrupt).
-
-       4a. Common problem with this type of sleep appears to be:
-               local_irq_disable();
-               if (!need_resched()) {
-                       local_irq_enable();
-                       *** resched interrupt arrives here ***
-                       __asm__("sleep until next interrupt");
-               }
-
-5. TIF_POLLING_NRFLAG can be set by idle routines that do not
-   need an interrupt to wake them up when need_resched goes high.
-   In other words, they must be periodically polling need_resched,
-   although it may be reasonable to do some background work or enter
-   a low CPU priority.
-
-       5a. If TIF_POLLING_NRFLAG is set, and we do decide to enter
-           an interrupt sleep, it needs to be cleared then a memory
-           barrier issued (followed by a test of need_resched with
-           interrupts disabled, as explained in 3).
-
-arch/i386/kernel/process.c has examples of both polling and
-sleeping idle functions.
-
-
-Possible arch/ problems
-=======================
-
-Possible arch problems I found (and either tried to fix or didn't):
-
-h8300 - Is such sleeping racy vs interrupts? (See #4a).
-        The H8/300 manual I found indicates yes, however disabling IRQs
-        over the sleep mean only NMIs can wake it up, so can't fix easily
-        without doing spin waiting.
-
-ia64 - is safe_halt call racy vs interrupts? (does it sleep?) (See #4a)
-
-sh64 - Is sleeping racy vs interrupts? (See #4a)
-
-sparc - IRQs on at this point(?), change local_irq_save to _disable.
-      - TODO: needs secondary CPUs to disable preempt (See #1)
-
diff --git a/Documentation/sched-coding.txt b/Documentation/sched-coding.txt
deleted file mode 100644 (file)
index cbd8db7..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-     Reference for various scheduler-related methods in the O(1) scheduler
-               Robert Love <rml@tech9.net>, MontaVista Software
-
-
-Note most of these methods are local to kernel/sched.c - this is by design.
-The scheduler is meant to be self-contained and abstracted away.  This document
-is primarily for understanding the scheduler, not interfacing to it.  Some of
-the discussed interfaces, however, are general process/scheduling methods.
-They are typically defined in include/linux/sched.h.
-
-
-Main Scheduling Methods
------------------------
-
-void load_balance(runqueue_t *this_rq, int idle)
-       Attempts to pull tasks from one cpu to another to balance cpu usage,
-       if needed.  This method is called explicitly if the runqueues are
-       imbalanced or periodically by the timer tick.  Prior to calling,
-       the current runqueue must be locked and interrupts disabled.
-
-void schedule()
-       The main scheduling function.  Upon return, the highest priority
-       process will be active.
-
-
-Locking
--------
-
-Each runqueue has its own lock, rq->lock.  When multiple runqueues need
-to be locked, lock acquires must be ordered by ascending &runqueue value.
-
-A specific runqueue is locked via
-
-       task_rq_lock(task_t pid, unsigned long *flags)
-
-which disables preemption, disables interrupts, and locks the runqueue pid is
-running on.  Likewise,
-
-       task_rq_unlock(task_t pid, unsigned long *flags)
-
-unlocks the runqueue pid is running on, restores interrupts to their previous
-state, and reenables preemption.
-
-The routines
-
-       double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
-
-and
-
-       double_rq_unlock(runqueue_t *rq1, runqueue_t *rq2)
-
-safely lock and unlock, respectively, the two specified runqueues.  They do
-not, however, disable and restore interrupts.  Users are required to do so
-manually before and after calls.
-
-
-Values
-------
-
-MAX_PRIO
-       The maximum priority of the system, stored in the task as task->prio.
-       Lower priorities are higher.  Normal (non-RT) priorities range from
-       MAX_RT_PRIO to (MAX_PRIO - 1).
-MAX_RT_PRIO
-       The maximum real-time priority of the system.  Valid RT priorities
-       range from 0 to (MAX_RT_PRIO - 1).
-MAX_USER_RT_PRIO
-       The maximum real-time priority that is exported to user-space.  Should
-       always be equal to or less than MAX_RT_PRIO.  Setting it less allows
-       kernel threads to have higher priorities than any user-space task.
-MIN_TIMESLICE
-MAX_TIMESLICE
-       Respectively, the minimum and maximum timeslices (quanta) of a process.
-
-Data
-----
-
-struct runqueue
-       The main per-CPU runqueue data structure.
-struct task_struct
-       The main per-process data structure.
-
-
-General Methods
----------------
-
-cpu_rq(cpu)
-       Returns the runqueue of the specified cpu.
-this_rq()
-       Returns the runqueue of the current cpu.
-task_rq(pid)
-       Returns the runqueue which holds the specified pid.
-cpu_curr(cpu)
-       Returns the task currently running on the given cpu.
-rt_task(pid)
-       Returns true if pid is real-time, false if not.
-
-
-Process Control Methods
------------------------
-
-void set_user_nice(task_t *p, long nice)
-       Sets the "nice" value of task p to the given value.
-int setscheduler(pid_t pid, int policy, struct sched_param *param)
-       Sets the scheduling policy and parameters for the given pid.
-int set_cpus_allowed(task_t *p, unsigned long new_mask)
-       Sets a given task's CPU affinity and migrates it to a proper cpu.
-       Callers must have a valid reference to the task and assure the
-       task not exit prematurely.  No locks can be held during the call.
-set_task_state(tsk, state_value)
-       Sets the given task's state to the given value.
-set_current_state(state_value)
-       Sets the current task's state to the given value.
-void set_tsk_need_resched(struct task_struct *tsk)
-       Sets need_resched in the given task.
-void clear_tsk_need_resched(struct task_struct *tsk)
-       Clears need_resched in the given task.
-void set_need_resched()
-       Sets need_resched in the current task.
-void clear_need_resched()
-       Clears need_resched in the current task.
-int need_resched()
-       Returns true if need_resched is set in the current task, false
-       otherwise.
-yield()
-       Place the current process at the end of the runqueue and call schedule.
diff --git a/Documentation/sched-design-CFS.txt b/Documentation/sched-design-CFS.txt
deleted file mode 100644 (file)
index 88bcb87..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-
-This is the CFS scheduler.
-
-80% of CFS's design can be summed up in a single sentence: CFS basically
-models an "ideal, precise multi-tasking CPU" on real hardware.
-
-"Ideal multi-tasking CPU" is a (non-existent  :-))  CPU that has 100%
-physical power and which can run each task at precise equal speed, in
-parallel, each at 1/nr_running speed. For example: if there are 2 tasks
-running then it runs each at 50% physical power - totally in parallel.
-
-On real hardware, we can run only a single task at once, so while that
-one task runs, the other tasks that are waiting for the CPU are at a
-disadvantage - the current task gets an unfair amount of CPU time. In
-CFS this fairness imbalance is expressed and tracked via the per-task
-p->wait_runtime (nanosec-unit) value. "wait_runtime" is the amount of
-time the task should now run on the CPU for it to become completely fair
-and balanced.
-
-( small detail: on 'ideal' hardware, the p->wait_runtime value would
-  always be zero - no task would ever get 'out of balance' from the
-  'ideal' share of CPU time. )
-
-CFS's task picking logic is based on this p->wait_runtime value and it
-is thus very simple: it always tries to run the task with the largest
-p->wait_runtime value. In other words, CFS tries to run the task with
-the 'gravest need' for more CPU time. So CFS always tries to split up
-CPU time between runnable tasks as close to 'ideal multitasking
-hardware' as possible.
-
-Most of the rest of CFS's design just falls out of this really simple
-concept, with a few add-on embellishments like nice levels,
-multiprocessing and various algorithm variants to recognize sleepers.
-
-In practice it works like this: the system runs a task a bit, and when
-the task schedules (or a scheduler tick happens) the task's CPU usage is
-'accounted for': the (small) time it just spent using the physical CPU
-is deducted from p->wait_runtime. [minus the 'fair share' it would have
-gotten anyway]. Once p->wait_runtime gets low enough so that another
-task becomes the 'leftmost task' of the time-ordered rbtree it maintains
-(plus a small amount of 'granularity' distance relative to the leftmost
-task so that we do not over-schedule tasks and trash the cache) then the
-new leftmost task is picked and the current task is preempted.
-
-The rq->fair_clock value tracks the 'CPU time a runnable task would have
-fairly gotten, had it been runnable during that time'. So by using
-rq->fair_clock values we can accurately timestamp and measure the
-'expected CPU time' a task should have gotten. All runnable tasks are
-sorted in the rbtree by the "rq->fair_clock - p->wait_runtime" key, and
-CFS picks the 'leftmost' task and sticks to it. As the system progresses
-forwards, newly woken tasks are put into the tree more and more to the
-right - slowly but surely giving a chance for every task to become the
-'leftmost task' and thus get on the CPU within a deterministic amount of
-time.
-
-Some implementation details:
-
- - the introduction of Scheduling Classes: an extensible hierarchy of
-   scheduler modules. These modules encapsulate scheduling policy
-   details and are handled by the scheduler core without the core
-   code assuming about them too much.
-
- - sched_fair.c implements the 'CFS desktop scheduler': it is a
-   replacement for the vanilla scheduler's SCHED_OTHER interactivity
-   code.
-
-   I'd like to give credit to Con Kolivas for the general approach here:
-   he has proven via RSDL/SD that 'fair scheduling' is possible and that
-   it results in better desktop scheduling. Kudos Con!
-
-   The CFS patch uses a completely different approach and implementation
-   from RSDL/SD. My goal was to make CFS's interactivity quality exceed
-   that of RSDL/SD, which is a high standard to meet :-) Testing
-   feedback is welcome to decide this one way or another. [ and, in any
-   case, all of SD's logic could be added via a kernel/sched_sd.c module
-   as well, if Con is interested in such an approach. ]
-
-   CFS's design is quite radical: it does not use runqueues, it uses a
-   time-ordered rbtree to build a 'timeline' of future task execution,
-   and thus has no 'array switch' artifacts (by which both the vanilla
-   scheduler and RSDL/SD are affected).
-
-   CFS uses nanosecond granularity accounting and does not rely on any
-   jiffies or other HZ detail. Thus the CFS scheduler has no notion of
-   'timeslices' and has no heuristics whatsoever. There is only one
-   central tunable (you have to switch on CONFIG_SCHED_DEBUG):
-
-         /proc/sys/kernel/sched_granularity_ns
-
-   which can be used to tune the scheduler from 'desktop' (low
-   latencies) to 'server' (good batching) workloads. It defaults to a
-   setting suitable for desktop workloads. SCHED_BATCH is handled by the
-   CFS scheduler module too.
-
-   Due to its design, the CFS scheduler is not prone to any of the
-   'attacks' that exist today against the heuristics of the stock
-   scheduler: fiftyp.c, thud.c, chew.c, ring-test.c, massive_intr.c all
-   work fine and do not impact interactivity and produce the expected
-   behavior.
-
-   the CFS scheduler has a much stronger handling of nice levels and
-   SCHED_BATCH: both types of workloads should be isolated much more
-   agressively than under the vanilla scheduler.
-
-   ( another detail: due to nanosec accounting and timeline sorting,
-     sched_yield() support is very simple under CFS, and in fact under
-     CFS sched_yield() behaves much better than under any other
-     scheduler i have tested so far. )
-
- - sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler
-   way than the vanilla scheduler does. It uses 100 runqueues (for all
-   100 RT priority levels, instead of 140 in the vanilla scheduler)
-   and it needs no expired array.
-
- - reworked/sanitized SMP load-balancing: the runqueue-walking
-   assumptions are gone from the load-balancing code now, and
-   iterators of the scheduling modules are used. The balancing code got
-   quite a bit simpler as a result.
-
-
-Group scheduler extension to CFS
-================================
-
-Normally the scheduler operates on individual tasks and strives to provide
-fair CPU time to each task. Sometimes, it may be desirable to group tasks
-and provide fair CPU time to each such task group. For example, it may
-be desirable to first provide fair CPU time to each user on the system
-and then to each task belonging to a user.
-
-CONFIG_FAIR_GROUP_SCHED strives to achieve exactly that. It lets
-SCHED_NORMAL/BATCH tasks be be grouped and divides CPU time fairly among such
-groups. At present, there are two (mutually exclusive) mechanisms to group
-tasks for CPU bandwidth control purpose:
-
-       - Based on user id (CONFIG_FAIR_USER_SCHED)
-               In this option, tasks are grouped according to their user id.
-       - Based on "cgroup" pseudo filesystem (CONFIG_FAIR_CGROUP_SCHED)
-               This options lets the administrator create arbitrary groups
-               of tasks, using the "cgroup" pseudo filesystem. See
-               Documentation/cgroups.txt for more information about this
-               filesystem.
-
-Only one of these options to group tasks can be chosen and not both.
-
-Group scheduler tunables:
-
-When CONFIG_FAIR_USER_SCHED is defined, a directory is created in sysfs for
-each new user and a "cpu_share" file is added in that directory.
-
-       # cd /sys/kernel/uids
-       # cat 512/cpu_share             # Display user 512's CPU share
-       1024
-       # echo 2048 > 512/cpu_share     # Modify user 512's CPU share
-       # cat 512/cpu_share             # Display user 512's CPU share
-       2048
-       #
-
-CPU bandwidth between two users are divided in the ratio of their CPU shares.
-For ex: if you would like user "root" to get twice the bandwidth of user
-"guest", then set the cpu_share for both the users such that "root"'s
-cpu_share is twice "guest"'s cpu_share
-
-
-When CONFIG_FAIR_CGROUP_SCHED is defined, a "cpu.shares" file is created
-for each group created using the pseudo filesystem. See example steps
-below to create task groups and modify their CPU share using the "cgroups"
-pseudo filesystem
-
-       # mkdir /dev/cpuctl
-       # mount -t cgroup -ocpu none /dev/cpuctl
-       # cd /dev/cpuctl
-
-       # mkdir multimedia      # create "multimedia" group of tasks
-       # mkdir browser         # create "browser" group of tasks
-
-       # #Configure the multimedia group to receive twice the CPU bandwidth
-       # #that of browser group
-
-       # echo 2048 > multimedia/cpu.shares
-       # echo 1024 > browser/cpu.shares
-
-       # firefox &     # Launch firefox and move it to "browser" group
-       # echo <firefox_pid> > browser/tasks
-
-       # #Launch gmplayer (or your favourite movie player)
-       # echo <movie_player_pid> > multimedia/tasks
diff --git a/Documentation/sched-design.txt b/Documentation/sched-design.txt
deleted file mode 100644 (file)
index 1605bf0..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-                  Goals, Design and Implementation of the
-                     new ultra-scalable O(1) scheduler
-
-
-  This is an edited version of an email Ingo Molnar sent to
-  lkml on 4 Jan 2002.  It describes the goals, design, and
-  implementation of Ingo's new ultra-scalable O(1) scheduler.
-  Last Updated: 18 April 2002.
-
-
-Goal
-====
-
-The main goal of the new scheduler is to keep all the good things we know
-and love about the current Linux scheduler:
-
- - good interactive performance even during high load: if the user
-   types or clicks then the system must react instantly and must execute
-   the user tasks smoothly, even during considerable background load.
-
- - good scheduling/wakeup performance with 1-2 runnable processes.
-
- - fairness: no process should stay without any timeslice for any
-   unreasonable amount of time. No process should get an unjustly high
-   amount of CPU time.
-
- - priorities: less important tasks can be started with lower priority,
-   more important tasks with higher priority.
-
- - SMP efficiency: no CPU should stay idle if there is work to do.
-
- - SMP affinity: processes which run on one CPU should stay affine to
-   that CPU. Processes should not bounce between CPUs too frequently.
-
- - plus additional scheduler features: RT scheduling, CPU binding.
-
-and the goal is also to add a few new things:
-
- - fully O(1) scheduling. Are you tired of the recalculation loop
-   blowing the L1 cache away every now and then? Do you think the goodness
-   loop is taking a bit too long to finish if there are lots of runnable
-   processes? This new scheduler takes no prisoners: wakeup(), schedule(),
-   the timer interrupt are all O(1) algorithms. There is no recalculation
-   loop. There is no goodness loop either.
-
- - 'perfect' SMP scalability. With the new scheduler there is no 'big'
-   runqueue_lock anymore - it's all per-CPU runqueues and locks - two
-   tasks on two separate CPUs can wake up, schedule and context-switch
-   completely in parallel, without any interlocking. All
-   scheduling-relevant data is structured for maximum scalability.
-
- - better SMP affinity. The old scheduler has a particular weakness that
-   causes the random bouncing of tasks between CPUs if/when higher
-   priority/interactive tasks, this was observed and reported by many
-   people. The reason is that the timeslice recalculation loop first needs
-   every currently running task to consume its timeslice. But when this
-   happens on eg. an 8-way system, then this property starves an
-   increasing number of CPUs from executing any process. Once the last
-   task that has a timeslice left has finished using up that timeslice,
-   the recalculation loop is triggered and other CPUs can start executing
-   tasks again - after having idled around for a number of timer ticks.
-   The more CPUs, the worse this effect.
-
-   Furthermore, this same effect causes the bouncing effect as well:
-   whenever there is such a 'timeslice squeeze' of the global runqueue,
-   idle processors start executing tasks which are not affine to that CPU.
-   (because the affine tasks have finished off their timeslices already.)
-
-   The new scheduler solves this problem by distributing timeslices on a
-   per-CPU basis, without having any global synchronization or
-   recalculation.
-
- - batch scheduling. A significant proportion of computing-intensive tasks
-   benefit from batch-scheduling, where timeslices are long and processes
-   are roundrobin scheduled. The new scheduler does such batch-scheduling
-   of the lowest priority tasks - so nice +19 jobs will get
-   'batch-scheduled' automatically. With this scheduler, nice +19 jobs are
-   in essence SCHED_IDLE, from an interactiveness point of view.
-
- - handle extreme loads more smoothly, without breakdown and scheduling
-   storms.
-
- - O(1) RT scheduling. For those RT folks who are paranoid about the
-   O(nr_running) property of the goodness loop and the recalculation loop.
-
- - run fork()ed children before the parent. Andrea has pointed out the
-   advantages of this a few months ago, but patches for this feature
-   do not work with the old scheduler as well as they should,
-   because idle processes often steal the new child before the fork()ing
-   CPU gets to execute it.
-
-
-Design
-======
-
-The core of the new scheduler contains the following mechanisms:
-
- - *two* priority-ordered 'priority arrays' per CPU. There is an 'active'
-   array and an 'expired' array. The active array contains all tasks that
-   are affine to this CPU and have timeslices left. The expired array
-   contains all tasks which have used up their timeslices - but this array
-   is kept sorted as well. The active and expired array is not accessed
-   directly, it's accessed through two pointers in the per-CPU runqueue
-   structure. If all active tasks are used up then we 'switch' the two
-   pointers and from now on the ready-to-go (former-) expired array is the
-   active array - and the empty active array serves as the new collector
-   for expired tasks.
-
- - there is a 64-bit bitmap cache for array indices. Finding the highest
-   priority task is thus a matter of two x86 BSFL bit-search instructions.
-
-the split-array solution enables us to have an arbitrary number of active
-and expired tasks, and the recalculation of timeslices can be done
-immediately when the timeslice expires. Because the arrays are always
-access through the pointers in the runqueue, switching the two arrays can
-be done very quickly.
-
-this is a hybride priority-list approach coupled with roundrobin
-scheduling and the array-switch method of distributing timeslices.
-
- - there is a per-task 'load estimator'.
-
-one of the toughest things to get right is good interactive feel during
-heavy system load. While playing with various scheduler variants i found
-that the best interactive feel is achieved not by 'boosting' interactive
-tasks, but by 'punishing' tasks that want to use more CPU time than there
-is available. This method is also much easier to do in an O(1) fashion.
-
-to establish the actual 'load' the task contributes to the system, a
-complex-looking but pretty accurate method is used: there is a 4-entry
-'history' ringbuffer of the task's activities during the last 4 seconds.
-This ringbuffer is operated without much overhead. The entries tell the
-scheduler a pretty accurate load-history of the task: has it used up more
-CPU time or less during the past N seconds. [the size '4' and the interval
-of 4x 1 seconds was found by lots of experimentation - this part is
-flexible and can be changed in both directions.]
-
-the penalty a task gets for generating more load than the CPU can handle
-is a priority decrease - there is a maximum amount to this penalty
-relative to their static priority, so even fully CPU-bound tasks will
-observe each other's priorities, and will share the CPU accordingly.
-
-the SMP load-balancer can be extended/switched with additional parallel
-computing and cache hierarchy concepts: NUMA scheduling, multi-core CPUs
-can be supported easily by changing the load-balancer. Right now it's
-tuned for my SMP systems.
-
-i skipped the prev->mm == next->mm advantage - no workload i know of shows
-any sensitivity to this. It can be added back by sacrificing O(1)
-schedule() [the current and one-lower priority list can be searched for a
-that->mm == current->mm condition], but costs a fair number of cycles
-during a number of important workloads, so i wanted to avoid this as much
-as possible.
-
-- the SMP idle-task startup code was still racy and the new scheduler
-triggered this. So i streamlined the idle-setup code a bit. We do not call
-into schedule() before all processors have started up fully and all idle
-threads are in place.
-
-- the patch also cleans up a number of aspects of sched.c - moves code
-into other areas of the kernel where it's appropriate, and simplifies
-certain code paths and data constructs. As a result, the new scheduler's
-code is smaller than the old one.
-
-       Ingo
diff --git a/Documentation/sched-domains.txt b/Documentation/sched-domains.txt
deleted file mode 100644 (file)
index a9e990a..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-Each CPU has a "base" scheduling domain (struct sched_domain). These are
-accessed via cpu_sched_domain(i) and this_sched_domain() macros. The domain
-hierarchy is built from these base domains via the ->parent pointer. ->parent
-MUST be NULL terminated, and domain structures should be per-CPU as they
-are locklessly updated.
-
-Each scheduling domain spans a number of CPUs (stored in the ->span field).
-A domain's span MUST be a superset of it child's span (this restriction could
-be relaxed if the need arises), and a base domain for CPU i MUST span at least
-i. The top domain for each CPU will generally span all CPUs in the system
-although strictly it doesn't have to, but this could lead to a case where some
-CPUs will never be given tasks to run unless the CPUs allowed mask is
-explicitly set. A sched domain's span means "balance process load among these
-CPUs".
-
-Each scheduling domain must have one or more CPU groups (struct sched_group)
-which are organised as a circular one way linked list from the ->groups
-pointer. The union of cpumasks of these groups MUST be the same as the
-domain's span. The intersection of cpumasks from any two of these groups
-MUST be the empty set. The group pointed to by the ->groups pointer MUST
-contain the CPU to which the domain belongs. Groups may be shared among
-CPUs as they contain read only data after they have been set up.
-
-Balancing within a sched domain occurs between groups. That is, each group
-is treated as one entity. The load of a group is defined as the sum of the
-load of each of its member CPUs, and only when the load of a group becomes
-out of balance are tasks moved between groups.
-
-In kernel/sched.c, rebalance_tick is run periodically on each CPU. This
-function takes its CPU's base sched domain and checks to see if has reached
-its rebalance interval. If so, then it will run load_balance on that domain.
-rebalance_tick then checks the parent sched_domain (if it exists), and the
-parent of the parent and so forth.
-
-*** Implementing sched domains ***
-The "base" domain will "span" the first level of the hierarchy. In the case
-of SMT, you'll span all siblings of the physical CPU, with each group being
-a single virtual CPU.
-
-In SMP, the parent of the base domain will span all physical CPUs in the
-node. Each group being a single physical CPU. Then with NUMA, the parent
-of the SMP domain will span the entire machine, with each group having the
-cpumask of a node. Or, you could do multi-level NUMA or Opteron, for example,
-might have just one domain covering its one NUMA level.
-
-The implementor should read comments in include/linux/sched.h:
-struct sched_domain fields, SD_FLAG_*, SD_*_INIT to get an idea of
-the specifics and what to tune.
-
-For SMT, the architecture must define CONFIG_SCHED_SMT and provide a
-cpumask_t cpu_sibling_map[NR_CPUS], where cpu_sibling_map[i] is the mask of
-all "i"'s siblings as well as "i" itself.
-
-Architectures may retain the regular override the default SD_*_INIT flags
-while using the generic domain builder in kernel/sched.c if they wish to
-retain the traditional SMT->SMP->NUMA topology (or some subset of that). This
-can be done by #define'ing ARCH_HASH_SCHED_TUNE.
-
-Alternatively, the architecture may completely override the generic domain
-builder by #define'ing ARCH_HASH_SCHED_DOMAIN, and exporting your
-arch_init_sched_domains function. This function will attach domains to all
-CPUs using cpu_attach_domain.
-
-Implementors should change the line
-#undef SCHED_DOMAIN_DEBUG
-to
-#define SCHED_DOMAIN_DEBUG
-in kernel/sched.c as this enables an error checking parse of the sched domains
-which should catch most possible errors (described above). It also prints out
-the domain structure in a visual format.
diff --git a/Documentation/sched-nice-design.txt b/Documentation/sched-nice-design.txt
deleted file mode 100644 (file)
index e2bae5a..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-This document explains the thinking about the revamped and streamlined
-nice-levels implementation in the new Linux scheduler.
-
-Nice levels were always pretty weak under Linux and people continuously
-pestered us to make nice +19 tasks use up much less CPU time.
-
-Unfortunately that was not that easy to implement under the old
-scheduler, (otherwise we'd have done it long ago) because nice level
-support was historically coupled to timeslice length, and timeslice
-units were driven by the HZ tick, so the smallest timeslice was 1/HZ.
-
-In the O(1) scheduler (in 2003) we changed negative nice levels to be
-much stronger than they were before in 2.4 (and people were happy about
-that change), and we also intentionally calibrated the linear timeslice
-rule so that nice +19 level would be _exactly_ 1 jiffy. To better
-understand it, the timeslice graph went like this (cheesy ASCII art
-alert!):
-
-
-                   A
-             \     | [timeslice length]
-              \    |
-               \   |
-                \  |
-                 \ |
-                  \|___100msecs
-                   |^ . _
-                   |      ^ . _
-                   |            ^ . _
- -*----------------------------------*-----> [nice level]
- -20               |                +19
-                   |
-                   |
-
-So that if someone wanted to really renice tasks, +19 would give a much
-bigger hit than the normal linear rule would do. (The solution of
-changing the ABI to extend priorities was discarded early on.)
-
-This approach worked to some degree for some time, but later on with
-HZ=1000 it caused 1 jiffy to be 1 msec, which meant 0.1% CPU usage which
-we felt to be a bit excessive. Excessive _not_ because it's too small of
-a CPU utilization, but because it causes too frequent (once per
-millisec) rescheduling. (and would thus trash the cache, etc. Remember,
-this was long ago when hardware was weaker and caches were smaller, and
-people were running number crunching apps at nice +19.)
-
-So for HZ=1000 we changed nice +19 to 5msecs, because that felt like the
-right minimal granularity - and this translates to 5% CPU utilization.
-But the fundamental HZ-sensitive property for nice+19 still remained,
-and we never got a single complaint about nice +19 being too _weak_ in
-terms of CPU utilization, we only got complaints about it (still) being
-too _strong_ :-)
-
-To sum it up: we always wanted to make nice levels more consistent, but
-within the constraints of HZ and jiffies and their nasty design level
-coupling to timeslices and granularity it was not really viable.
-
-The second (less frequent but still periodically occuring) complaint
-about Linux's nice level support was its assymetry around the origo
-(which you can see demonstrated in the picture above), or more
-accurately: the fact that nice level behavior depended on the _absolute_
-nice level as well, while the nice API itself is fundamentally
-"relative":
-
-   int nice(int inc);
-
-   asmlinkage long sys_nice(int increment)
-
-(the first one is the glibc API, the second one is the syscall API.)
-Note that the 'inc' is relative to the current nice level. Tools like
-bash's "nice" command mirror this relative API.
-
-With the old scheduler, if you for example started a niced task with +1
-and another task with +2, the CPU split between the two tasks would
-depend on the nice level of the parent shell - if it was at nice -10 the
-CPU split was different than if it was at +5 or +10.
-
-A third complaint against Linux's nice level support was that negative
-nice levels were not 'punchy enough', so lots of people had to resort to
-run audio (and other multimedia) apps under RT priorities such as
-SCHED_FIFO. But this caused other problems: SCHED_FIFO is not starvation
-proof, and a buggy SCHED_FIFO app can also lock up the system for good.
-
-The new scheduler in v2.6.23 addresses all three types of complaints:
-
-To address the first complaint (of nice levels being not "punchy"
-enough), the scheduler was decoupled from 'time slice' and HZ concepts
-(and granularity was made a separate concept from nice levels) and thus
-it was possible to implement better and more consistent nice +19
-support: with the new scheduler nice +19 tasks get a HZ-independent
-1.5%, instead of the variable 3%-5%-9% range they got in the old
-scheduler.
-
-To address the second complaint (of nice levels not being consistent),
-the new scheduler makes nice(1) have the same CPU utilization effect on
-tasks, regardless of their absolute nice levels. So on the new
-scheduler, running a nice +10 and a nice 11 task has the same CPU
-utilization "split" between them as running a nice -5 and a nice -4
-task. (one will get 55% of the CPU, the other 45%.) That is why nice
-levels were changed to be "multiplicative" (or exponential) - that way
-it does not matter which nice level you start out from, the 'relative
-result' will always be the same.
-
-The third complaint (of negative nice levels not being "punchy" enough
-and forcing audio apps to run under the more dangerous SCHED_FIFO
-scheduling policy) is addressed by the new scheduler almost
-automatically: stronger negative nice levels are an automatic
-side-effect of the recalibrated dynamic range of nice levels.
diff --git a/Documentation/sched-stats.txt b/Documentation/sched-stats.txt
deleted file mode 100644 (file)
index 442e14d..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-Version 14 of schedstats includes support for sched_domains, which hit the
-mainline kernel in 2.6.20 although it is identical to the stats from version
-12 which was in the kernel from 2.6.13-2.6.19 (version 13 never saw a kernel
-release).  Some counters make more sense to be per-runqueue; other to be
-per-domain.  Note that domains (and their associated information) will only
-be pertinent and available on machines utilizing CONFIG_SMP.
-
-In version 14 of schedstat, there is at least one level of domain
-statistics for each cpu listed, and there may well be more than one
-domain.  Domains have no particular names in this implementation, but
-the highest numbered one typically arbitrates balancing across all the
-cpus on the machine, while domain0 is the most tightly focused domain,
-sometimes balancing only between pairs of cpus.  At this time, there
-are no architectures which need more than three domain levels. The first
-field in the domain stats is a bit map indicating which cpus are affected
-by that domain.
-
-These fields are counters, and only increment.  Programs which make use
-of these will need to start with a baseline observation and then calculate
-the change in the counters at each subsequent observation.  A perl script
-which does this for many of the fields is available at
-
-    http://eaglet.rain.com/rick/linux/schedstat/
-
-Note that any such script will necessarily be version-specific, as the main
-reason to change versions is changes in the output format.  For those wishing
-to write their own scripts, the fields are described here.
-
-CPU statistics
---------------
-cpu<N> 1 2 3 4 5 6 7 8 9 10 11 12
-
-NOTE: In the sched_yield() statistics, the active queue is considered empty
-    if it has only one process in it, since obviously the process calling
-    sched_yield() is that process.
-
-First four fields are sched_yield() statistics:
-     1) # of times both the active and the expired queue were empty
-     2) # of times just the active queue was empty
-     3) # of times just the expired queue was empty
-     4) # of times sched_yield() was called
-
-Next three are schedule() statistics:
-     5) # of times we switched to the expired queue and reused it
-     6) # of times schedule() was called
-     7) # of times schedule() left the processor idle
-
-Next two are try_to_wake_up() statistics:
-     8) # of times try_to_wake_up() was called
-     9) # of times try_to_wake_up() was called to wake up the local cpu
-
-Next three are statistics describing scheduling latency:
-    10) sum of all time spent running by tasks on this processor (in jiffies)
-    11) sum of all time spent waiting to run by tasks on this processor (in
-        jiffies)
-    12) # of timeslices run on this cpu
-
-
-Domain statistics
------------------
-One of these is produced per domain for each cpu described. (Note that if
-CONFIG_SMP is not defined, *no* domains are utilized and these lines
-will not appear in the output.)
-
-domain<N> <cpumask> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
-
-The first field is a bit mask indicating what cpus this domain operates over.
-
-The next 24 are a variety of load_balance() statistics in grouped into types
-of idleness (idle, busy, and newly idle):
-
-     1) # of times in this domain load_balance() was called when the
-        cpu was idle
-     2) # of times in this domain load_balance() checked but found
-        the load did not require balancing when the cpu was idle
-     3) # of times in this domain load_balance() tried to move one or
-        more tasks and failed, when the cpu was idle
-     4) sum of imbalances discovered (if any) with each call to
-        load_balance() in this domain when the cpu was idle
-     5) # of times in this domain pull_task() was called when the cpu
-        was idle
-     6) # of times in this domain pull_task() was called even though
-        the target task was cache-hot when idle
-     7) # of times in this domain load_balance() was called but did
-        not find a busier queue while the cpu was idle
-     8) # of times in this domain a busier queue was found while the
-        cpu was idle but no busier group was found
-
-     9) # of times in this domain load_balance() was called when the
-        cpu was busy
-    10) # of times in this domain load_balance() checked but found the
-        load did not require balancing when busy
-    11) # of times in this domain load_balance() tried to move one or
-        more tasks and failed, when the cpu was busy
-    12) sum of imbalances discovered (if any) with each call to
-        load_balance() in this domain when the cpu was busy
-    13) # of times in this domain pull_task() was called when busy
-    14) # of times in this domain pull_task() was called even though the
-        target task was cache-hot when busy
-    15) # of times in this domain load_balance() was called but did not
-        find a busier queue while the cpu was busy
-    16) # of times in this domain a busier queue was found while the cpu
-        was busy but no busier group was found
-
-    17) # of times in this domain load_balance() was called when the
-        cpu was just becoming idle
-    18) # of times in this domain load_balance() checked but found the
-        load did not require balancing when the cpu was just becoming idle
-    19) # of times in this domain load_balance() tried to move one or more
-        tasks and failed, when the cpu was just becoming idle
-    20) sum of imbalances discovered (if any) with each call to
-        load_balance() in this domain when the cpu was just becoming idle
-    21) # of times in this domain pull_task() was called when newly idle
-    22) # of times in this domain pull_task() was called even though the
-        target task was cache-hot when just becoming idle
-    23) # of times in this domain load_balance() was called but did not
-        find a busier queue while the cpu was just becoming idle
-    24) # of times in this domain a busier queue was found while the cpu
-        was just becoming idle but no busier group was found
-
-   Next three are active_load_balance() statistics:
-    25) # of times active_load_balance() was called
-    26) # of times active_load_balance() tried to move a task and failed
-    27) # of times active_load_balance() successfully moved a task
-
-   Next three are sched_balance_exec() statistics:
-    28) sbe_cnt is not used
-    29) sbe_balanced is not used
-    30) sbe_pushed is not used
-
-   Next three are sched_balance_fork() statistics:
-    31) sbf_cnt is not used
-    32) sbf_balanced is not used
-    33) sbf_pushed is not used
-
-   Next three are try_to_wake_up() statistics:
-    34) # of times in this domain try_to_wake_up() awoke a task that
-        last ran on a different cpu in this domain
-    35) # of times in this domain try_to_wake_up() moved a task to the
-        waking cpu because it was cache-cold on its own cpu anyway
-    36) # of times in this domain try_to_wake_up() started passive balancing
-
-/proc/<pid>/schedstat
-----------------
-schedstats also adds a new /proc/<pid/schedstat file to include some of
-the same information on a per-process level.  There are three fields in
-this file correlating for that process to:
-     1) time spent on the cpu
-     2) time spent waiting on a runqueue
-     3) # of timeslices run on this cpu
-
-A program could be easily written to make use of these extra fields to
-report on how well a particular process or set of processes is faring
-under the scheduler's policies.  A simple version of such a program is
-available at
-    http://eaglet.rain.com/rick/linux/schedstat/v12/latency.c
diff --git a/Documentation/scheduler/00-INDEX b/Documentation/scheduler/00-INDEX
new file mode 100644 (file)
index 0000000..b5f5ca0
--- /dev/null
@@ -0,0 +1,16 @@
+00-INDEX
+       - this file.
+sched-arch.txt
+       - CPU Scheduler implementation hints for architecture specific code.
+sched-coding.txt
+       - reference for various scheduler-related methods in the O(1) scheduler.
+sched-design.txt
+       - goals, design and implementation of the Linux O(1) scheduler.
+sched-design-CFS.txt
+       - goals, design and implementation of the Complete Fair Scheduler.
+sched-domains.txt
+       - information on scheduling domains.
+sched-nice-design.txt
+       - How and why the scheduler's nice levels are implemented.
+sched-stats.txt
+       - information on schedstats (Linux Scheduler Statistics).
diff --git a/Documentation/scheduler/sched-arch.txt b/Documentation/scheduler/sched-arch.txt
new file mode 100644 (file)
index 0000000..941615a
--- /dev/null
@@ -0,0 +1,89 @@
+       CPU Scheduler implementation hints for architecture specific code
+
+       Nick Piggin, 2005
+
+Context switch
+==============
+1. Runqueue locking
+By default, the switch_to arch function is called with the runqueue
+locked. This is usually not a problem unless switch_to may need to
+take the runqueue lock. This is usually due to a wake up operation in
+the context switch. See include/asm-ia64/system.h for an example.
+
+To request the scheduler call switch_to with the runqueue unlocked,
+you must `#define __ARCH_WANT_UNLOCKED_CTXSW` in a header file
+(typically the one where switch_to is defined).
+
+Unlocked context switches introduce only a very minor performance
+penalty to the core scheduler implementation in the CONFIG_SMP case.
+
+2. Interrupt status
+By default, the switch_to arch function is called with interrupts
+disabled. Interrupts may be enabled over the call if it is likely to
+introduce a significant interrupt latency by adding the line
+`#define __ARCH_WANT_INTERRUPTS_ON_CTXSW` in the same place as for
+unlocked context switches. This define also implies
+`__ARCH_WANT_UNLOCKED_CTXSW`. See include/asm-arm/system.h for an
+example.
+
+
+CPU idle
+========
+Your cpu_idle routines need to obey the following rules:
+
+1. Preempt should now disabled over idle routines. Should only
+   be enabled to call schedule() then disabled again.
+
+2. need_resched/TIF_NEED_RESCHED is only ever set, and will never
+   be cleared until the running task has called schedule(). Idle
+   threads need only ever query need_resched, and may never set or
+   clear it.
+
+3. When cpu_idle finds (need_resched() == 'true'), it should call
+   schedule(). It should not call schedule() otherwise.
+
+4. The only time interrupts need to be disabled when checking
+   need_resched is if we are about to sleep the processor until
+   the next interrupt (this doesn't provide any protection of
+   need_resched, it prevents losing an interrupt).
+
+       4a. Common problem with this type of sleep appears to be:
+               local_irq_disable();
+               if (!need_resched()) {
+                       local_irq_enable();
+                       *** resched interrupt arrives here ***
+                       __asm__("sleep until next interrupt");
+               }
+
+5. TIF_POLLING_NRFLAG can be set by idle routines that do not
+   need an interrupt to wake them up when need_resched goes high.
+   In other words, they must be periodically polling need_resched,
+   although it may be reasonable to do some background work or enter
+   a low CPU priority.
+
+       5a. If TIF_POLLING_NRFLAG is set, and we do decide to enter
+           an interrupt sleep, it needs to be cleared then a memory
+           barrier issued (followed by a test of need_resched with
+           interrupts disabled, as explained in 3).
+
+arch/i386/kernel/process.c has examples of both polling and
+sleeping idle functions.
+
+
+Possible arch/ problems
+=======================
+
+Possible arch problems I found (and either tried to fix or didn't):
+
+h8300 - Is such sleeping racy vs interrupts? (See #4a).
+        The H8/300 manual I found indicates yes, however disabling IRQs
+        over the sleep mean only NMIs can wake it up, so can't fix easily
+        without doing spin waiting.
+
+ia64 - is safe_halt call racy vs interrupts? (does it sleep?) (See #4a)
+
+sh64 - Is sleeping racy vs interrupts? (See #4a)
+
+sparc - IRQs on at this point(?), change local_irq_save to _disable.
+      - TODO: needs secondary CPUs to disable preempt (See #1)
+
diff --git a/Documentation/scheduler/sched-coding.txt b/Documentation/scheduler/sched-coding.txt
new file mode 100644 (file)
index 0000000..cbd8db7
--- /dev/null
@@ -0,0 +1,126 @@
+     Reference for various scheduler-related methods in the O(1) scheduler
+               Robert Love <rml@tech9.net>, MontaVista Software
+
+
+Note most of these methods are local to kernel/sched.c - this is by design.
+The scheduler is meant to be self-contained and abstracted away.  This document
+is primarily for understanding the scheduler, not interfacing to it.  Some of
+the discussed interfaces, however, are general process/scheduling methods.
+They are typically defined in include/linux/sched.h.
+
+
+Main Scheduling Methods
+-----------------------
+
+void load_balance(runqueue_t *this_rq, int idle)
+       Attempts to pull tasks from one cpu to another to balance cpu usage,
+       if needed.  This method is called explicitly if the runqueues are
+       imbalanced or periodically by the timer tick.  Prior to calling,
+       the current runqueue must be locked and interrupts disabled.
+
+void schedule()
+       The main scheduling function.  Upon return, the highest priority
+       process will be active.
+
+
+Locking
+-------
+
+Each runqueue has its own lock, rq->lock.  When multiple runqueues need
+to be locked, lock acquires must be ordered by ascending &runqueue value.
+
+A specific runqueue is locked via
+
+       task_rq_lock(task_t pid, unsigned long *flags)
+
+which disables preemption, disables interrupts, and locks the runqueue pid is
+running on.  Likewise,
+
+       task_rq_unlock(task_t pid, unsigned long *flags)
+
+unlocks the runqueue pid is running on, restores interrupts to their previous
+state, and reenables preemption.
+
+The routines
+
+       double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
+
+and
+
+       double_rq_unlock(runqueue_t *rq1, runqueue_t *rq2)
+
+safely lock and unlock, respectively, the two specified runqueues.  They do
+not, however, disable and restore interrupts.  Users are required to do so
+manually before and after calls.
+
+
+Values
+------
+
+MAX_PRIO
+       The maximum priority of the system, stored in the task as task->prio.
+       Lower priorities are higher.  Normal (non-RT) priorities range from
+       MAX_RT_PRIO to (MAX_PRIO - 1).
+MAX_RT_PRIO
+       The maximum real-time priority of the system.  Valid RT priorities
+       range from 0 to (MAX_RT_PRIO - 1).
+MAX_USER_RT_PRIO
+       The maximum real-time priority that is exported to user-space.  Should
+       always be equal to or less than MAX_RT_PRIO.  Setting it less allows
+       kernel threads to have higher priorities than any user-space task.
+MIN_TIMESLICE
+MAX_TIMESLICE
+       Respectively, the minimum and maximum timeslices (quanta) of a process.
+
+Data
+----
+
+struct runqueue
+       The main per-CPU runqueue data structure.
+struct task_struct
+       The main per-process data structure.
+
+
+General Methods
+---------------
+
+cpu_rq(cpu)
+       Returns the runqueue of the specified cpu.
+this_rq()
+       Returns the runqueue of the current cpu.
+task_rq(pid)
+       Returns the runqueue which holds the specified pid.
+cpu_curr(cpu)
+       Returns the task currently running on the given cpu.
+rt_task(pid)
+       Returns true if pid is real-time, false if not.
+
+
+Process Control Methods
+-----------------------
+
+void set_user_nice(task_t *p, long nice)
+       Sets the "nice" value of task p to the given value.
+int setscheduler(pid_t pid, int policy, struct sched_param *param)
+       Sets the scheduling policy and parameters for the given pid.
+int set_cpus_allowed(task_t *p, unsigned long new_mask)
+       Sets a given task's CPU affinity and migrates it to a proper cpu.
+       Callers must have a valid reference to the task and assure the
+       task not exit prematurely.  No locks can be held during the call.
+set_task_state(tsk, state_value)
+       Sets the given task's state to the given value.
+set_current_state(state_value)
+       Sets the current task's state to the given value.
+void set_tsk_need_resched(struct task_struct *tsk)
+       Sets need_resched in the given task.
+void clear_tsk_need_resched(struct task_struct *tsk)
+       Clears need_resched in the given task.
+void set_need_resched()
+       Sets need_resched in the current task.
+void clear_need_resched()
+       Clears need_resched in the current task.
+int need_resched()
+       Returns true if need_resched is set in the current task, false
+       otherwise.
+yield()
+       Place the current process at the end of the runqueue and call schedule.
diff --git a/Documentation/scheduler/sched-design-CFS.txt b/Documentation/scheduler/sched-design-CFS.txt
new file mode 100644 (file)
index 0000000..88bcb87
--- /dev/null
@@ -0,0 +1,186 @@
+
+This is the CFS scheduler.
+
+80% of CFS's design can be summed up in a single sentence: CFS basically
+models an "ideal, precise multi-tasking CPU" on real hardware.
+
+"Ideal multi-tasking CPU" is a (non-existent  :-))  CPU that has 100%
+physical power and which can run each task at precise equal speed, in
+parallel, each at 1/nr_running speed. For example: if there are 2 tasks
+running then it runs each at 50% physical power - totally in parallel.
+
+On real hardware, we can run only a single task at once, so while that
+one task runs, the other tasks that are waiting for the CPU are at a
+disadvantage - the current task gets an unfair amount of CPU time. In
+CFS this fairness imbalance is expressed and tracked via the per-task
+p->wait_runtime (nanosec-unit) value. "wait_runtime" is the amount of
+time the task should now run on the CPU for it to become completely fair
+and balanced.
+
+( small detail: on 'ideal' hardware, the p->wait_runtime value would
+  always be zero - no task would ever get 'out of balance' from the
+  'ideal' share of CPU time. )
+
+CFS's task picking logic is based on this p->wait_runtime value and it
+is thus very simple: it always tries to run the task with the largest
+p->wait_runtime value. In other words, CFS tries to run the task with
+the 'gravest need' for more CPU time. So CFS always tries to split up
+CPU time between runnable tasks as close to 'ideal multitasking
+hardware' as possible.
+
+Most of the rest of CFS's design just falls out of this really simple
+concept, with a few add-on embellishments like nice levels,
+multiprocessing and various algorithm variants to recognize sleepers.
+
+In practice it works like this: the system runs a task a bit, and when
+the task schedules (or a scheduler tick happens) the task's CPU usage is
+'accounted for': the (small) time it just spent using the physical CPU
+is deducted from p->wait_runtime. [minus the 'fair share' it would have
+gotten anyway]. Once p->wait_runtime gets low enough so that another
+task becomes the 'leftmost task' of the time-ordered rbtree it maintains
+(plus a small amount of 'granularity' distance relative to the leftmost
+task so that we do not over-schedule tasks and trash the cache) then the
+new leftmost task is picked and the current task is preempted.
+
+The rq->fair_clock value tracks the 'CPU time a runnable task would have
+fairly gotten, had it been runnable during that time'. So by using
+rq->fair_clock values we can accurately timestamp and measure the
+'expected CPU time' a task should have gotten. All runnable tasks are
+sorted in the rbtree by the "rq->fair_clock - p->wait_runtime" key, and
+CFS picks the 'leftmost' task and sticks to it. As the system progresses
+forwards, newly woken tasks are put into the tree more and more to the
+right - slowly but surely giving a chance for every task to become the
+'leftmost task' and thus get on the CPU within a deterministic amount of
+time.
+
+Some implementation details:
+
+ - the introduction of Scheduling Classes: an extensible hierarchy of
+   scheduler modules. These modules encapsulate scheduling policy
+   details and are handled by the scheduler core without the core
+   code assuming about them too much.
+
+ - sched_fair.c implements the 'CFS desktop scheduler': it is a
+   replacement for the vanilla scheduler's SCHED_OTHER interactivity
+   code.
+
+   I'd like to give credit to Con Kolivas for the general approach here:
+   he has proven via RSDL/SD that 'fair scheduling' is possible and that
+   it results in better desktop scheduling. Kudos Con!
+
+   The CFS patch uses a completely different approach and implementation
+   from RSDL/SD. My goal was to make CFS's interactivity quality exceed
+   that of RSDL/SD, which is a high standard to meet :-) Testing
+   feedback is welcome to decide this one way or another. [ and, in any
+   case, all of SD's logic could be added via a kernel/sched_sd.c module
+   as well, if Con is interested in such an approach. ]
+
+   CFS's design is quite radical: it does not use runqueues, it uses a
+   time-ordered rbtree to build a 'timeline' of future task execution,
+   and thus has no 'array switch' artifacts (by which both the vanilla
+   scheduler and RSDL/SD are affected).
+
+   CFS uses nanosecond granularity accounting and does not rely on any
+   jiffies or other HZ detail. Thus the CFS scheduler has no notion of
+   'timeslices' and has no heuristics whatsoever. There is only one
+   central tunable (you have to switch on CONFIG_SCHED_DEBUG):
+
+         /proc/sys/kernel/sched_granularity_ns
+
+   which can be used to tune the scheduler from 'desktop' (low
+   latencies) to 'server' (good batching) workloads. It defaults to a
+   setting suitable for desktop workloads. SCHED_BATCH is handled by the
+   CFS scheduler module too.
+
+   Due to its design, the CFS scheduler is not prone to any of the
+   'attacks' that exist today against the heuristics of the stock
+   scheduler: fiftyp.c, thud.c, chew.c, ring-test.c, massive_intr.c all
+   work fine and do not impact interactivity and produce the expected
+   behavior.
+
+   the CFS scheduler has a much stronger handling of nice levels and
+   SCHED_BATCH: both types of workloads should be isolated much more
+   agressively than under the vanilla scheduler.
+
+   ( another detail: due to nanosec accounting and timeline sorting,
+     sched_yield() support is very simple under CFS, and in fact under
+     CFS sched_yield() behaves much better than under any other
+     scheduler i have tested so far. )
+
+ - sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler
+   way than the vanilla scheduler does. It uses 100 runqueues (for all
+   100 RT priority levels, instead of 140 in the vanilla scheduler)
+   and it needs no expired array.
+
+ - reworked/sanitized SMP load-balancing: the runqueue-walking
+   assumptions are gone from the load-balancing code now, and
+   iterators of the scheduling modules are used. The balancing code got
+   quite a bit simpler as a result.
+
+
+Group scheduler extension to CFS
+================================
+
+Normally the scheduler operates on individual tasks and strives to provide
+fair CPU time to each task. Sometimes, it may be desirable to group tasks
+and provide fair CPU time to each such task group. For example, it may
+be desirable to first provide fair CPU time to each user on the system
+and then to each task belonging to a user.
+
+CONFIG_FAIR_GROUP_SCHED strives to achieve exactly that. It lets
+SCHED_NORMAL/BATCH tasks be be grouped and divides CPU time fairly among such
+groups. At present, there are two (mutually exclusive) mechanisms to group
+tasks for CPU bandwidth control purpose:
+
+       - Based on user id (CONFIG_FAIR_USER_SCHED)
+               In this option, tasks are grouped according to their user id.
+       - Based on "cgroup" pseudo filesystem (CONFIG_FAIR_CGROUP_SCHED)
+               This options lets the administrator create arbitrary groups
+               of tasks, using the "cgroup" pseudo filesystem. See
+               Documentation/cgroups.txt for more information about this
+               filesystem.
+
+Only one of these options to group tasks can be chosen and not both.
+
+Group scheduler tunables:
+
+When CONFIG_FAIR_USER_SCHED is defined, a directory is created in sysfs for
+each new user and a "cpu_share" file is added in that directory.
+
+       # cd /sys/kernel/uids
+       # cat 512/cpu_share             # Display user 512's CPU share
+       1024
+       # echo 2048 > 512/cpu_share     # Modify user 512's CPU share
+       # cat 512/cpu_share             # Display user 512's CPU share
+       2048
+       #
+
+CPU bandwidth between two users are divided in the ratio of their CPU shares.
+For ex: if you would like user "root" to get twice the bandwidth of user
+"guest", then set the cpu_share for both the users such that "root"'s
+cpu_share is twice "guest"'s cpu_share
+
+
+When CONFIG_FAIR_CGROUP_SCHED is defined, a "cpu.shares" file is created
+for each group created using the pseudo filesystem. See example steps
+below to create task groups and modify their CPU share using the "cgroups"
+pseudo filesystem
+
+       # mkdir /dev/cpuctl
+       # mount -t cgroup -ocpu none /dev/cpuctl
+       # cd /dev/cpuctl
+
+       # mkdir multimedia      # create "multimedia" group of tasks
+       # mkdir browser         # create "browser" group of tasks
+
+       # #Configure the multimedia group to receive twice the CPU bandwidth
+       # #that of browser group
+
+       # echo 2048 > multimedia/cpu.shares
+       # echo 1024 > browser/cpu.shares
+
+       # firefox &     # Launch firefox and move it to "browser" group
+       # echo <firefox_pid> > browser/tasks
+
+       # #Launch gmplayer (or your favourite movie player)
+       # echo <movie_player_pid> > multimedia/tasks
diff --git a/Documentation/scheduler/sched-design.txt b/Documentation/scheduler/sched-design.txt
new file mode 100644 (file)
index 0000000..1605bf0
--- /dev/null
@@ -0,0 +1,165 @@
+                  Goals, Design and Implementation of the
+                     new ultra-scalable O(1) scheduler
+
+
+  This is an edited version of an email Ingo Molnar sent to
+  lkml on 4 Jan 2002.  It describes the goals, design, and
+  implementation of Ingo's new ultra-scalable O(1) scheduler.
+  Last Updated: 18 April 2002.
+
+
+Goal
+====
+
+The main goal of the new scheduler is to keep all the good things we know
+and love about the current Linux scheduler:
+
+ - good interactive performance even during high load: if the user
+   types or clicks then the system must react instantly and must execute
+   the user tasks smoothly, even during considerable background load.
+
+ - good scheduling/wakeup performance with 1-2 runnable processes.
+
+ - fairness: no process should stay without any timeslice for any
+   unreasonable amount of time. No process should get an unjustly high
+   amount of CPU time.
+
+ - priorities: less important tasks can be started with lower priority,
+   more important tasks with higher priority.
+
+ - SMP efficiency: no CPU should stay idle if there is work to do.
+
+ - SMP affinity: processes which run on one CPU should stay affine to
+   that CPU. Processes should not bounce between CPUs too frequently.
+
+ - plus additional scheduler features: RT scheduling, CPU binding.
+
+and the goal is also to add a few new things:
+
+ - fully O(1) scheduling. Are you tired of the recalculation loop
+   blowing the L1 cache away every now and then? Do you think the goodness
+   loop is taking a bit too long to finish if there are lots of runnable
+   processes? This new scheduler takes no prisoners: wakeup(), schedule(),
+   the timer interrupt are all O(1) algorithms. There is no recalculation
+   loop. There is no goodness loop either.
+
+ - 'perfect' SMP scalability. With the new scheduler there is no 'big'
+   runqueue_lock anymore - it's all per-CPU runqueues and locks - two
+   tasks on two separate CPUs can wake up, schedule and context-switch
+   completely in parallel, without any interlocking. All
+   scheduling-relevant data is structured for maximum scalability.
+
+ - better SMP affinity. The old scheduler has a particular weakness that
+   causes the random bouncing of tasks between CPUs if/when higher
+   priority/interactive tasks, this was observed and reported by many
+   people. The reason is that the timeslice recalculation loop first needs
+   every currently running task to consume its timeslice. But when this
+   happens on eg. an 8-way system, then this property starves an
+   increasing number of CPUs from executing any process. Once the last
+   task that has a timeslice left has finished using up that timeslice,
+   the recalculation loop is triggered and other CPUs can start executing
+   tasks again - after having idled around for a number of timer ticks.
+   The more CPUs, the worse this effect.
+
+   Furthermore, this same effect causes the bouncing effect as well:
+   whenever there is such a 'timeslice squeeze' of the global runqueue,
+   idle processors start executing tasks which are not affine to that CPU.
+   (because the affine tasks have finished off their timeslices already.)
+
+   The new scheduler solves this problem by distributing timeslices on a
+   per-CPU basis, without having any global synchronization or
+   recalculation.
+
+ - batch scheduling. A significant proportion of computing-intensive tasks
+   benefit from batch-scheduling, where timeslices are long and processes
+   are roundrobin scheduled. The new scheduler does such batch-scheduling
+   of the lowest priority tasks - so nice +19 jobs will get
+   'batch-scheduled' automatically. With this scheduler, nice +19 jobs are
+   in essence SCHED_IDLE, from an interactiveness point of view.
+
+ - handle extreme loads more smoothly, without breakdown and scheduling
+   storms.
+
+ - O(1) RT scheduling. For those RT folks who are paranoid about the
+   O(nr_running) property of the goodness loop and the recalculation loop.
+
+ - run fork()ed children before the parent. Andrea has pointed out the
+   advantages of this a few months ago, but patches for this feature
+   do not work with the old scheduler as well as they should,
+   because idle processes often steal the new child before the fork()ing
+   CPU gets to execute it.
+
+
+Design
+======
+
+The core of the new scheduler contains the following mechanisms:
+
+ - *two* priority-ordered 'priority arrays' per CPU. There is an 'active'
+   array and an 'expired' array. The active array contains all tasks that
+   are affine to this CPU and have timeslices left. The expired array
+   contains all tasks which have used up their timeslices - but this array
+   is kept sorted as well. The active and expired array is not accessed
+   directly, it's accessed through two pointers in the per-CPU runqueue
+   structure. If all active tasks are used up then we 'switch' the two
+   pointers and from now on the ready-to-go (former-) expired array is the
+   active array - and the empty active array serves as the new collector
+   for expired tasks.
+
+ - there is a 64-bit bitmap cache for array indices. Finding the highest
+   priority task is thus a matter of two x86 BSFL bit-search instructions.
+
+the split-array solution enables us to have an arbitrary number of active
+and expired tasks, and the recalculation of timeslices can be done
+immediately when the timeslice expires. Because the arrays are always
+access through the pointers in the runqueue, switching the two arrays can
+be done very quickly.
+
+this is a hybride priority-list approach coupled with roundrobin
+scheduling and the array-switch method of distributing timeslices.
+
+ - there is a per-task 'load estimator'.
+
+one of the toughest things to get right is good interactive feel during
+heavy system load. While playing with various scheduler variants i found
+that the best interactive feel is achieved not by 'boosting' interactive
+tasks, but by 'punishing' tasks that want to use more CPU time than there
+is available. This method is also much easier to do in an O(1) fashion.
+
+to establish the actual 'load' the task contributes to the system, a
+complex-looking but pretty accurate method is used: there is a 4-entry
+'history' ringbuffer of the task's activities during the last 4 seconds.
+This ringbuffer is operated without much overhead. The entries tell the
+scheduler a pretty accurate load-history of the task: has it used up more
+CPU time or less during the past N seconds. [the size '4' and the interval
+of 4x 1 seconds was found by lots of experimentation - this part is
+flexible and can be changed in both directions.]
+
+the penalty a task gets for generating more load than the CPU can handle
+is a priority decrease - there is a maximum amount to this penalty
+relative to their static priority, so even fully CPU-bound tasks will
+observe each other's priorities, and will share the CPU accordingly.
+
+the SMP load-balancer can be extended/switched with additional parallel
+computing and cache hierarchy concepts: NUMA scheduling, multi-core CPUs
+can be supported easily by changing the load-balancer. Right now it's
+tuned for my SMP systems.
+
+i skipped the prev->mm == next->mm advantage - no workload i know of shows
+any sensitivity to this. It can be added back by sacrificing O(1)
+schedule() [the current and one-lower priority list can be searched for a
+that->mm == current->mm condition], but costs a fair number of cycles
+during a number of important workloads, so i wanted to avoid this as much
+as possible.
+
+- the SMP idle-task startup code was still racy and the new scheduler
+triggered this. So i streamlined the idle-setup code a bit. We do not call
+into schedule() before all processors have started up fully and all idle
+threads are in place.
+
+- the patch also cleans up a number of aspects of sched.c - moves code
+into other areas of the kernel where it's appropriate, and simplifies
+certain code paths and data constructs. As a result, the new scheduler's
+code is smaller than the old one.
+
+       Ingo
diff --git a/Documentation/scheduler/sched-domains.txt b/Documentation/scheduler/sched-domains.txt
new file mode 100644 (file)
index 0000000..a9e990a
--- /dev/null
@@ -0,0 +1,70 @@
+Each CPU has a "base" scheduling domain (struct sched_domain). These are
+accessed via cpu_sched_domain(i) and this_sched_domain() macros. The domain
+hierarchy is built from these base domains via the ->parent pointer. ->parent
+MUST be NULL terminated, and domain structures should be per-CPU as they
+are locklessly updated.
+
+Each scheduling domain spans a number of CPUs (stored in the ->span field).
+A domain's span MUST be a superset of it child's span (this restriction could
+be relaxed if the need arises), and a base domain for CPU i MUST span at least
+i. The top domain for each CPU will generally span all CPUs in the system
+although strictly it doesn't have to, but this could lead to a case where some
+CPUs will never be given tasks to run unless the CPUs allowed mask is
+explicitly set. A sched domain's span means "balance process load among these
+CPUs".
+
+Each scheduling domain must have one or more CPU groups (struct sched_group)
+which are organised as a circular one way linked list from the ->groups
+pointer. The union of cpumasks of these groups MUST be the same as the
+domain's span. The intersection of cpumasks from any two of these groups
+MUST be the empty set. The group pointed to by the ->groups pointer MUST
+contain the CPU to which the domain belongs. Groups may be shared among
+CPUs as they contain read only data after they have been set up.
+
+Balancing within a sched domain occurs between groups. That is, each group
+is treated as one entity. The load of a group is defined as the sum of the
+load of each of its member CPUs, and only when the load of a group becomes
+out of balance are tasks moved between groups.
+
+In kernel/sched.c, rebalance_tick is run periodically on each CPU. This
+function takes its CPU's base sched domain and checks to see if has reached
+its rebalance interval. If so, then it will run load_balance on that domain.
+rebalance_tick then checks the parent sched_domain (if it exists), and the
+parent of the parent and so forth.
+
+*** Implementing sched domains ***
+The "base" domain will "span" the first level of the hierarchy. In the case
+of SMT, you'll span all siblings of the physical CPU, with each group being
+a single virtual CPU.
+
+In SMP, the parent of the base domain will span all physical CPUs in the
+node. Each group being a single physical CPU. Then with NUMA, the parent
+of the SMP domain will span the entire machine, with each group having the
+cpumask of a node. Or, you could do multi-level NUMA or Opteron, for example,
+might have just one domain covering its one NUMA level.
+
+The implementor should read comments in include/linux/sched.h:
+struct sched_domain fields, SD_FLAG_*, SD_*_INIT to get an idea of
+the specifics and what to tune.
+
+For SMT, the architecture must define CONFIG_SCHED_SMT and provide a
+cpumask_t cpu_sibling_map[NR_CPUS], where cpu_sibling_map[i] is the mask of
+all "i"'s siblings as well as "i" itself.
+
+Architectures may retain the regular override the default SD_*_INIT flags
+while using the generic domain builder in kernel/sched.c if they wish to
+retain the traditional SMT->SMP->NUMA topology (or some subset of that). This
+can be done by #define'ing ARCH_HASH_SCHED_TUNE.
+
+Alternatively, the architecture may completely override the generic domain
+builder by #define'ing ARCH_HASH_SCHED_DOMAIN, and exporting your
+arch_init_sched_domains function. This function will attach domains to all
+CPUs using cpu_attach_domain.
+
+Implementors should change the line
+#undef SCHED_DOMAIN_DEBUG
+to
+#define SCHED_DOMAIN_DEBUG
+in kernel/sched.c as this enables an error checking parse of the sched domains
+which should catch most possible errors (described above). It also prints out
+the domain structure in a visual format.
diff --git a/Documentation/scheduler/sched-nice-design.txt b/Documentation/scheduler/sched-nice-design.txt
new file mode 100644 (file)
index 0000000..e2bae5a
--- /dev/null
@@ -0,0 +1,108 @@
+This document explains the thinking about the revamped and streamlined
+nice-levels implementation in the new Linux scheduler.
+
+Nice levels were always pretty weak under Linux and people continuously
+pestered us to make nice +19 tasks use up much less CPU time.
+
+Unfortunately that was not that easy to implement under the old
+scheduler, (otherwise we'd have done it long ago) because nice level
+support was historically coupled to timeslice length, and timeslice
+units were driven by the HZ tick, so the smallest timeslice was 1/HZ.
+
+In the O(1) scheduler (in 2003) we changed negative nice levels to be
+much stronger than they were before in 2.4 (and people were happy about
+that change), and we also intentionally calibrated the linear timeslice
+rule so that nice +19 level would be _exactly_ 1 jiffy. To better
+understand it, the timeslice graph went like this (cheesy ASCII art
+alert!):
+
+
+                   A
+             \     | [timeslice length]
+              \    |
+               \   |
+                \  |
+                 \ |
+                  \|___100msecs
+                   |^ . _
+                   |      ^ . _
+                   |            ^ . _
+ -*----------------------------------*-----> [nice level]
+ -20               |                +19
+                   |
+                   |
+
+So that if someone wanted to really renice tasks, +19 would give a much
+bigger hit than the normal linear rule would do. (The solution of
+changing the ABI to extend priorities was discarded early on.)
+
+This approach worked to some degree for some time, but later on with
+HZ=1000 it caused 1 jiffy to be 1 msec, which meant 0.1% CPU usage which
+we felt to be a bit excessive. Excessive _not_ because it's too small of
+a CPU utilization, but because it causes too frequent (once per
+millisec) rescheduling. (and would thus trash the cache, etc. Remember,
+this was long ago when hardware was weaker and caches were smaller, and
+people were running number crunching apps at nice +19.)
+
+So for HZ=1000 we changed nice +19 to 5msecs, because that felt like the
+right minimal granularity - and this translates to 5% CPU utilization.
+But the fundamental HZ-sensitive property for nice+19 still remained,
+and we never got a single complaint about nice +19 being too _weak_ in
+terms of CPU utilization, we only got complaints about it (still) being
+too _strong_ :-)
+
+To sum it up: we always wanted to make nice levels more consistent, but
+within the constraints of HZ and jiffies and their nasty design level
+coupling to timeslices and granularity it was not really viable.
+
+The second (less frequent but still periodically occuring) complaint
+about Linux's nice level support was its assymetry around the origo
+(which you can see demonstrated in the picture above), or more
+accurately: the fact that nice level behavior depended on the _absolute_
+nice level as well, while the nice API itself is fundamentally
+"relative":
+
+   int nice(int inc);
+
+   asmlinkage long sys_nice(int increment)
+
+(the first one is the glibc API, the second one is the syscall API.)
+Note that the 'inc' is relative to the current nice level. Tools like
+bash's "nice" command mirror this relative API.
+
+With the old scheduler, if you for example started a niced task with +1
+and another task with +2, the CPU split between the two tasks would
+depend on the nice level of the parent shell - if it was at nice -10 the
+CPU split was different than if it was at +5 or +10.
+
+A third complaint against Linux's nice level support was that negative
+nice levels were not 'punchy enough', so lots of people had to resort to
+run audio (and other multimedia) apps under RT priorities such as
+SCHED_FIFO. But this caused other problems: SCHED_FIFO is not starvation
+proof, and a buggy SCHED_FIFO app can also lock up the system for good.
+
+The new scheduler in v2.6.23 addresses all three types of complaints:
+
+To address the first complaint (of nice levels being not "punchy"
+enough), the scheduler was decoupled from 'time slice' and HZ concepts
+(and granularity was made a separate concept from nice levels) and thus
+it was possible to implement better and more consistent nice +19
+support: with the new scheduler nice +19 tasks get a HZ-independent
+1.5%, instead of the variable 3%-5%-9% range they got in the old
+scheduler.
+
+To address the second complaint (of nice levels not being consistent),
+the new scheduler makes nice(1) have the same CPU utilization effect on
+tasks, regardless of their absolute nice levels. So on the new
+scheduler, running a nice +10 and a nice 11 task has the same CPU
+utilization "split" between them as running a nice -5 and a nice -4
+task. (one will get 55% of the CPU, the other 45%.) That is why nice
+levels were changed to be "multiplicative" (or exponential) - that way
+it does not matter which nice level you start out from, the 'relative
+result' will always be the same.
+
+The third complaint (of negative nice levels not being "punchy" enough
+and forcing audio apps to run under the more dangerous SCHED_FIFO
+scheduling policy) is addressed by the new scheduler almost
+automatically: stronger negative nice levels are an automatic
+side-effect of the recalibrated dynamic range of nice levels.
diff --git a/Documentation/scheduler/sched-stats.txt b/Documentation/scheduler/sched-stats.txt
new file mode 100644 (file)
index 0000000..442e14d
--- /dev/null
@@ -0,0 +1,156 @@
+Version 14 of schedstats includes support for sched_domains, which hit the
+mainline kernel in 2.6.20 although it is identical to the stats from version
+12 which was in the kernel from 2.6.13-2.6.19 (version 13 never saw a kernel
+release).  Some counters make more sense to be per-runqueue; other to be
+per-domain.  Note that domains (and their associated information) will only
+be pertinent and available on machines utilizing CONFIG_SMP.
+
+In version 14 of schedstat, there is at least one level of domain
+statistics for each cpu listed, and there may well be more than one
+domain.  Domains have no particular names in this implementation, but
+the highest numbered one typically arbitrates balancing across all the
+cpus on the machine, while domain0 is the most tightly focused domain,
+sometimes balancing only between pairs of cpus.  At this time, there
+are no architectures which need more than three domain levels. The first
+field in the domain stats is a bit map indicating which cpus are affected
+by that domain.
+
+These fields are counters, and only increment.  Programs which make use
+of these will need to start with a baseline observation and then calculate
+the change in the counters at each subsequent observation.  A perl script
+which does this for many of the fields is available at
+
+    http://eaglet.rain.com/rick/linux/schedstat/
+
+Note that any such script will necessarily be version-specific, as the main
+reason to change versions is changes in the output format.  For those wishing
+to write their own scripts, the fields are described here.
+
+CPU statistics
+--------------
+cpu<N> 1 2 3 4 5 6 7 8 9 10 11 12
+
+NOTE: In the sched_yield() statistics, the active queue is considered empty
+    if it has only one process in it, since obviously the process calling
+    sched_yield() is that process.
+
+First four fields are sched_yield() statistics:
+     1) # of times both the active and the expired queue were empty
+     2) # of times just the active queue was empty
+     3) # of times just the expired queue was empty
+     4) # of times sched_yield() was called
+
+Next three are schedule() statistics:
+     5) # of times we switched to the expired queue and reused it
+     6) # of times schedule() was called
+     7) # of times schedule() left the processor idle
+
+Next two are try_to_wake_up() statistics:
+     8) # of times try_to_wake_up() was called
+     9) # of times try_to_wake_up() was called to wake up the local cpu
+
+Next three are statistics describing scheduling latency:
+    10) sum of all time spent running by tasks on this processor (in jiffies)
+    11) sum of all time spent waiting to run by tasks on this processor (in
+        jiffies)
+    12) # of timeslices run on this cpu
+
+
+Domain statistics
+-----------------
+One of these is produced per domain for each cpu described. (Note that if
+CONFIG_SMP is not defined, *no* domains are utilized and these lines
+will not appear in the output.)
+
+domain<N> <cpumask> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
+
+The first field is a bit mask indicating what cpus this domain operates over.
+
+The next 24 are a variety of load_balance() statistics in grouped into types
+of idleness (idle, busy, and newly idle):
+
+     1) # of times in this domain load_balance() was called when the
+        cpu was idle
+     2) # of times in this domain load_balance() checked but found
+        the load did not require balancing when the cpu was idle
+     3) # of times in this domain load_balance() tried to move one or
+        more tasks and failed, when the cpu was idle
+     4) sum of imbalances discovered (if any) with each call to
+        load_balance() in this domain when the cpu was idle
+     5) # of times in this domain pull_task() was called when the cpu
+        was idle
+     6) # of times in this domain pull_task() was called even though
+        the target task was cache-hot when idle
+     7) # of times in this domain load_balance() was called but did
+        not find a busier queue while the cpu was idle
+     8) # of times in this domain a busier queue was found while the
+        cpu was idle but no busier group was found
+
+     9) # of times in this domain load_balance() was called when the
+        cpu was busy
+    10) # of times in this domain load_balance() checked but found the
+        load did not require balancing when busy
+    11) # of times in this domain load_balance() tried to move one or
+        more tasks and failed, when the cpu was busy
+    12) sum of imbalances discovered (if any) with each call to
+        load_balance() in this domain when the cpu was busy
+    13) # of times in this domain pull_task() was called when busy
+    14) # of times in this domain pull_task() was called even though the
+        target task was cache-hot when busy
+    15) # of times in this domain load_balance() was called but did not
+        find a busier queue while the cpu was busy
+    16) # of times in this domain a busier queue was found while the cpu
+        was busy but no busier group was found
+
+    17) # of times in this domain load_balance() was called when the
+        cpu was just becoming idle
+    18) # of times in this domain load_balance() checked but found the
+        load did not require balancing when the cpu was just becoming idle
+    19) # of times in this domain load_balance() tried to move one or more
+        tasks and failed, when the cpu was just becoming idle
+    20) sum of imbalances discovered (if any) with each call to
+        load_balance() in this domain when the cpu was just becoming idle
+    21) # of times in this domain pull_task() was called when newly idle
+    22) # of times in this domain pull_task() was called even though the
+        target task was cache-hot when just becoming idle
+    23) # of times in this domain load_balance() was called but did not
+        find a busier queue while the cpu was just becoming idle
+    24) # of times in this domain a busier queue was found while the cpu
+        was just becoming idle but no busier group was found
+
+   Next three are active_load_balance() statistics:
+    25) # of times active_load_balance() was called
+    26) # of times active_load_balance() tried to move a task and failed
+    27) # of times active_load_balance() successfully moved a task
+
+   Next three are sched_balance_exec() statistics:
+    28) sbe_cnt is not used
+    29) sbe_balanced is not used
+    30) sbe_pushed is not used
+
+   Next three are sched_balance_fork() statistics:
+    31) sbf_cnt is not used
+    32) sbf_balanced is not used
+    33) sbf_pushed is not used
+
+   Next three are try_to_wake_up() statistics:
+    34) # of times in this domain try_to_wake_up() awoke a task that
+        last ran on a different cpu in this domain
+    35) # of times in this domain try_to_wake_up() moved a task to the
+        waking cpu because it was cache-cold on its own cpu anyway
+    36) # of times in this domain try_to_wake_up() started passive balancing
+
+/proc/<pid>/schedstat
+----------------
+schedstats also adds a new /proc/<pid/schedstat file to include some of
+the same information on a per-process level.  There are three fields in
+this file correlating for that process to:
+     1) time spent on the cpu
+     2) time spent waiting on a runqueue
+     3) # of timeslices run on this cpu
+
+A program could be easily written to make use of these extra fields to
+report on how well a particular process or set of processes is faring
+under the scheduler's policies.  A simple version of such a program is
+available at
+    http://eaglet.rain.com/rick/linux/schedstat/v12/latency.c
diff --git a/Documentation/sharedsubtree.txt b/Documentation/sharedsubtree.txt
deleted file mode 100644 (file)
index 7365400..0000000
+++ /dev/null
@@ -1,1061 +0,0 @@
-Shared Subtrees
----------------
-
-Contents:
-       1) Overview
-       2) Features
-       3) smount command
-       4) Use-case
-       5) Detailed semantics
-       6) Quiz
-       7) FAQ
-       8) Implementation
-
-
-1) Overview
------------
-
-Consider the following situation:
-
-A process wants to clone its own namespace, but still wants to access the CD
-that got mounted recently.  Shared subtree semantics provide the necessary
-mechanism to accomplish the above.
-
-It provides the necessary building blocks for features like per-user-namespace
-and versioned filesystem.
-
-2) Features
------------
-
-Shared subtree provides four different flavors of mounts; struct vfsmount to be
-precise
-
-       a. shared mount
-       b. slave mount
-       c. private mount
-       d. unbindable mount
-
-
-2a) A shared mount can be replicated to as many mountpoints and all the
-replicas continue to be exactly same.
-
-       Here is an example:
-
-       Lets say /mnt has a mount that is shared.
-       mount --make-shared /mnt
-
-       note: mount command does not yet support the --make-shared flag.
-       I have included a small C program which does the same by executing
-       'smount /mnt shared'
-
-       #mount --bind /mnt /tmp
-       The above command replicates the mount at /mnt to the mountpoint /tmp
-       and the contents of both the mounts remain identical.
-
-       #ls /mnt
-       a b c
-
-       #ls /tmp
-       a b c
-
-       Now lets say we mount a device at /tmp/a
-       #mount /dev/sd0  /tmp/a
-
-       #ls /tmp/a
-       t1 t2 t2
-
-       #ls /mnt/a
-       t1 t2 t2
-
-       Note that the mount has propagated to the mount at /mnt as well.
-
-       And the same is true even when /dev/sd0 is mounted on /mnt/a. The
-       contents will be visible under /tmp/a too.
-
-
-2b) A slave mount is like a shared mount except that mount and umount events
-       only propagate towards it.
-
-       All slave mounts have a master mount which is a shared.
-
-       Here is an example:
-
-       Lets say /mnt has a mount which is shared.
-       #mount --make-shared /mnt
-
-       Lets bind mount /mnt to /tmp
-       #mount --bind /mnt /tmp
-
-       the new mount at /tmp becomes a shared mount and it is a replica of
-       the mount at /mnt.
-
-       Now lets make the mount at /tmp; a slave of /mnt
-       #mount --make-slave /tmp
-       [or smount /tmp slave]
-
-       lets mount /dev/sd0 on /mnt/a
-       #mount /dev/sd0 /mnt/a
-
-       #ls /mnt/a
-       t1 t2 t3
-
-       #ls /tmp/a
-       t1 t2 t3
-
-       Note the mount event has propagated to the mount at /tmp
-
-       However lets see what happens if we mount something on the mount at /tmp
-
-       #mount /dev/sd1 /tmp/b
-
-       #ls /tmp/b
-       s1 s2 s3
-
-       #ls /mnt/b
-
-       Note how the mount event has not propagated to the mount at
-       /mnt
-
-
-2c) A private mount does not forward or receive propagation.
-
-       This is the mount we are familiar with. Its the default type.
-
-
-2d) A unbindable mount is a unbindable private mount
-
-       lets say we have a mount at /mnt and we make is unbindable
-
-       #mount --make-unbindable /mnt
-        [ smount /mnt  unbindable ]
-
-        Lets try to bind mount this mount somewhere else.
-        # mount --bind /mnt /tmp
-        mount: wrong fs type, bad option, bad superblock on /mnt,
-               or too many mounted file systems
-
-       Binding a unbindable mount is a invalid operation.
-
-
-3) smount command
-
-       Currently the mount command is not aware of shared subtree features.
-       Work is in progress to add the support in mount ( util-linux package ).
-       Till then use the following program.
-
-       ------------------------------------------------------------------------
-       //
-       //this code was developed my Miklos Szeredi <miklos@szeredi.hu>
-       //and modified by Ram Pai <linuxram@us.ibm.com>
-       // sample usage:
-       //              smount /tmp shared
-       //
-       #include <stdio.h>
-       #include <stdlib.h>
-       #include <unistd.h>
-       #include <string.h>
-       #include <sys/mount.h>
-       #include <sys/fsuid.h>
-
-       #ifndef MS_REC
-       #define MS_REC          0x4000  /* 16384: Recursive loopback */
-       #endif
-
-       #ifndef MS_SHARED
-       #define MS_SHARED               1<<20   /* Shared */
-       #endif
-
-       #ifndef MS_PRIVATE
-       #define MS_PRIVATE              1<<18   /* Private */
-       #endif
-
-       #ifndef MS_SLAVE
-       #define MS_SLAVE                1<<19   /* Slave */
-       #endif
-
-       #ifndef MS_UNBINDABLE
-       #define MS_UNBINDABLE           1<<17   /* Unbindable */
-       #endif
-
-       int main(int argc, char *argv[])
-       {
-               int type;
-               if(argc != 3) {
-                       fprintf(stderr, "usage: %s dir "
-                       "<rshared|rslave|rprivate|runbindable|shared|slave"
-                       "|private|unbindable>\n" , argv[0]);
-                       return 1;
-               }
-
-               fprintf(stdout, "%s %s %s\n", argv[0], argv[1], argv[2]);
-
-               if (strcmp(argv[2],"rshared")==0)
-                       type=(MS_SHARED|MS_REC);
-               else if (strcmp(argv[2],"rslave")==0)
-                       type=(MS_SLAVE|MS_REC);
-               else if (strcmp(argv[2],"rprivate")==0)
-                       type=(MS_PRIVATE|MS_REC);
-               else if (strcmp(argv[2],"runbindable")==0)
-                       type=(MS_UNBINDABLE|MS_REC);
-               else if (strcmp(argv[2],"shared")==0)
-                       type=MS_SHARED;
-               else if (strcmp(argv[2],"slave")==0)
-                       type=MS_SLAVE;
-               else if (strcmp(argv[2],"private")==0)
-                       type=MS_PRIVATE;
-               else if (strcmp(argv[2],"unbindable")==0)
-                       type=MS_UNBINDABLE;
-               else {
-                       fprintf(stderr, "invalid operation: %s\n", argv[2]);
-                       return 1;
-               }
-               setfsuid(getuid());
-
-               if(mount("", argv[1], "dontcare", type, "") == -1) {
-                       perror("mount");
-                       return 1;
-               }
-               return 0;
-       }
-       -----------------------------------------------------------------------
-
-       Copy the above code snippet into smount.c
-       gcc -o smount smount.c
-
-
-       (i) To mark all the mounts under /mnt as shared execute the following
-       command:
-
-               smount /mnt rshared
-               the corresponding syntax planned for mount command is
-               mount --make-rshared /mnt
-
-           just to mark a mount /mnt as shared, execute the following
-           command:
-               smount /mnt shared
-               the corresponding syntax planned for mount command is
-               mount --make-shared /mnt
-
-       (ii) To mark all the shared mounts under /mnt as slave execute the
-       following
-
-            command:
-               smount /mnt rslave
-               the corresponding syntax planned for mount command is
-               mount --make-rslave /mnt
-
-           just to mark a mount /mnt as slave, execute the following
-           command:
-               smount /mnt slave
-               the corresponding syntax planned for mount command is
-               mount --make-slave /mnt
-
-       (iii) To mark all the mounts under /mnt as private execute the
-       following command:
-
-               smount /mnt rprivate
-               the corresponding syntax planned for mount command is
-               mount --make-rprivate /mnt
-
-           just to mark a mount /mnt as private, execute the following
-           command:
-               smount /mnt private
-               the corresponding syntax planned for mount command is
-               mount --make-private /mnt
-
-             NOTE: by default all the mounts are created as private. But if
-             you want to change some shared/slave/unbindable  mount as
-             private at a later point in time, this command can help.
-
-       (iv) To mark all the mounts under /mnt as unbindable execute the
-       following
-
-            command:
-               smount /mnt runbindable
-               the corresponding syntax planned for mount command is
-               mount --make-runbindable /mnt
-
-           just to mark a mount /mnt as unbindable, execute the following
-           command:
-               smount /mnt unbindable
-               the corresponding syntax planned for mount command is
-               mount --make-unbindable /mnt
-
-
-4) Use cases
-------------
-
-       A) A process wants to clone its own namespace, but still wants to
-          access the CD that got mounted recently.
-
-          Solution:
-
-               The system administrator can make the mount at /cdrom shared
-               mount --bind /cdrom /cdrom
-               mount --make-shared /cdrom
-
-               Now any process that clones off a new namespace will have a
-               mount at /cdrom which is a replica of the same mount in the
-               parent namespace.
-
-               So when a CD is inserted and mounted at /cdrom that mount gets
-               propagated to the other mount at /cdrom in all the other clone
-               namespaces.
-
-       B) A process wants its mounts invisible to any other process, but
-       still be able to see the other system mounts.
-
-          Solution:
-
-               To begin with, the administrator can mark the entire mount tree
-               as shareable.
-
-               mount --make-rshared /
-
-               A new process can clone off a new namespace. And mark some part
-               of its namespace as slave
-
-               mount --make-rslave /myprivatetree
-
-               Hence forth any mounts within the /myprivatetree done by the
-               process will not show up in any other namespace. However mounts
-               done in the parent namespace under /myprivatetree still shows
-               up in the process's namespace.
-
-
-       Apart from the above semantics this feature provides the
-       building blocks to solve the following problems:
-
-       C)  Per-user namespace
-
-               The above semantics allows a way to share mounts across
-               namespaces.  But namespaces are associated with processes. If
-               namespaces are made first class objects with user API to
-               associate/disassociate a namespace with userid, then each user
-               could have his/her own namespace and tailor it to his/her
-               requirements. Offcourse its needs support from PAM.
-
-       D)  Versioned files
-
-               If the entire mount tree is visible at multiple locations, then
-               a underlying versioning file system can return different
-               version of the file depending on the path used to access that
-               file.
-
-               An example is:
-
-               mount --make-shared /
-               mount --rbind / /view/v1
-               mount --rbind / /view/v2
-               mount --rbind / /view/v3
-               mount --rbind / /view/v4
-
-               and if /usr has a versioning filesystem mounted, than that
-               mount appears at /view/v1/usr, /view/v2/usr, /view/v3/usr and
-               /view/v4/usr too
-
-               A user can request v3 version of the file /usr/fs/namespace.c
-               by accessing /view/v3/usr/fs/namespace.c . The underlying
-               versioning filesystem can then decipher that v3 version of the
-               filesystem is being requested and return the corresponding
-               inode.
-
-5) Detailed semantics:
--------------------
-       The section below explains the detailed semantics of
-       bind, rbind, move, mount, umount and clone-namespace operations.
-
-       Note: the word 'vfsmount' and the noun 'mount' have been used
-       to mean the same thing, throughout this document.
-
-5a) Mount states
-
-       A given mount can be in one of the following states
-       1) shared
-       2) slave
-       3) shared and slave
-       4) private
-       5) unbindable
-
-       A 'propagation event' is defined as event generated on a vfsmount
-       that leads to mount or unmount actions in other vfsmounts.
-
-       A 'peer group' is defined as a group of vfsmounts that propagate
-       events to each other.
-
-       (1) Shared mounts
-
-               A 'shared mount' is defined as a vfsmount that belongs to a
-               'peer group'.
-
-               For example:
-                       mount --make-shared /mnt
-                       mount --bin /mnt /tmp
-
-               The mount at /mnt and that at /tmp are both shared and belong
-               to the same peer group. Anything mounted or unmounted under
-               /mnt or /tmp reflect in all the other mounts of its peer
-               group.
-
-
-       (2) Slave mounts
-
-               A 'slave mount' is defined as a vfsmount that receives
-               propagation events and does not forward propagation events.
-
-               A slave mount as the name implies has a master mount from which
-               mount/unmount events are received. Events do not propagate from
-               the slave mount to the master.  Only a shared mount can be made
-               a slave by executing the following command
-
-                       mount --make-slave mount
-
-               A shared mount that is made as a slave is no more shared unless
-               modified to become shared.
-
-       (3) Shared and Slave
-
-               A vfsmount can be both shared as well as slave.  This state
-               indicates that the mount is a slave of some vfsmount, and
-               has its own peer group too.  This vfsmount receives propagation
-               events from its master vfsmount, and also forwards propagation
-               events to its 'peer group' and to its slave vfsmounts.
-
-               Strictly speaking, the vfsmount is shared having its own
-               peer group, and this peer-group is a slave of some other
-               peer group.
-
-               Only a slave vfsmount can be made as 'shared and slave' by
-               either executing the following command
-                       mount --make-shared mount
-               or by moving the slave vfsmount under a shared vfsmount.
-
-       (4) Private mount
-
-               A 'private mount' is defined as vfsmount that does not
-               receive or forward any propagation events.
-
-       (5) Unbindable mount
-
-               A 'unbindable mount' is defined as vfsmount that does not
-               receive or forward any propagation events and cannot
-               be bind mounted.
-
-
-       State diagram:
-       The state diagram below explains the state transition of a mount,
-       in response to various commands.
-       ------------------------------------------------------------------------
-       |             |make-shared |  make-slave  | make-private |make-unbindab|
-       --------------|------------|--------------|--------------|-------------|
-       |shared       |shared      |*slave/private|   private    | unbindable  |
-       |             |            |              |              |             |
-       |-------------|------------|--------------|--------------|-------------|
-       |slave        |shared      |    **slave   |    private   | unbindable  |
-       |             |and slave   |              |              |             |
-       |-------------|------------|--------------|--------------|-------------|
-       |shared       |shared      |    slave     |    private   | unbindable  |
-       |and slave    |and slave   |              |              |             |
-       |-------------|------------|--------------|--------------|-------------|
-       |private      |shared      |  **private   |    private   | unbindable  |
-       |-------------|------------|--------------|--------------|-------------|
-       |unbindable   |shared      |**unbindable  |    private   | unbindable  |
-       ------------------------------------------------------------------------
-
-       * if the shared mount is the only mount in its peer group, making it
-       slave, makes it private automatically. Note that there is no master to
-       which it can be slaved to.
-
-       ** slaving a non-shared mount has no effect on the mount.
-
-       Apart from the commands listed below, the 'move' operation also changes
-       the state of a mount depending on type of the destination mount. Its
-       explained in section 5d.
-
-5b) Bind semantics
-
-       Consider the following command
-
-       mount --bind A/a  B/b
-
-       where 'A' is the source mount, 'a' is the dentry in the mount 'A', 'B'
-       is the destination mount and 'b' is the dentry in the destination mount.
-
-       The outcome depends on the type of mount of 'A' and 'B'. The table
-       below contains quick reference.
-   ---------------------------------------------------------------------------
-   |         BIND MOUNT OPERATION                                            |
-   |**************************************************************************
-   |source(A)->| shared       |       private  |       slave    | unbindable |
-   | dest(B)  |               |                |                |            |
-   |   |      |               |                |                |            |
-   |   v      |               |                |                |            |
-   |**************************************************************************
-   |  shared  | shared        |     shared     | shared & slave |  invalid   |
-   |          |               |                |                |            |
-   |non-shared| shared        |      private   |      slave     |  invalid   |
-   ***************************************************************************
-
-       Details:
-
-       1. 'A' is a shared mount and 'B' is a shared mount. A new mount 'C'
-       which is clone of 'A', is created. Its root dentry is 'a' . 'C' is
-       mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ...
-       are created and mounted at the dentry 'b' on all mounts where 'B'
-       propagates to. A new propagation tree containing 'C1',..,'Cn' is
-       created. This propagation tree is identical to the propagation tree of
-       'B'.  And finally the peer-group of 'C' is merged with the peer group
-       of 'A'.
-
-       2. 'A' is a private mount and 'B' is a shared mount. A new mount 'C'
-       which is clone of 'A', is created. Its root dentry is 'a'. 'C' is
-       mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ...
-       are created and mounted at the dentry 'b' on all mounts where 'B'
-       propagates to. A new propagation tree is set containing all new mounts
-       'C', 'C1', .., 'Cn' with exactly the same configuration as the
-       propagation tree for 'B'.
-
-       3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount. A new
-       mount 'C' which is clone of 'A', is created. Its root dentry is 'a' .
-       'C' is mounted on mount 'B' at dentry 'b'. Also new mounts 'C1', 'C2',
-       'C3' ... are created and mounted at the dentry 'b' on all mounts where
-       'B' propagates to. A new propagation tree containing the new mounts
-       'C','C1',..  'Cn' is created. This propagation tree is identical to the
-       propagation tree for 'B'. And finally the mount 'C' and its peer group
-       is made the slave of mount 'Z'.  In other words, mount 'C' is in the
-       state 'slave and shared'.
-
-       4. 'A' is a unbindable mount and 'B' is a shared mount. This is a
-       invalid operation.
-
-       5. 'A' is a private mount and 'B' is a non-shared(private or slave or
-       unbindable) mount. A new mount 'C' which is clone of 'A', is created.
-       Its root dentry is 'a'. 'C' is mounted on mount 'B' at dentry 'b'.
-
-       6. 'A' is a shared mount and 'B' is a non-shared mount. A new mount 'C'
-       which is a clone of 'A' is created. Its root dentry is 'a'. 'C' is
-       mounted on mount 'B' at dentry 'b'.  'C' is made a member of the
-       peer-group of 'A'.
-
-       7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount. A
-       new mount 'C' which is a clone of 'A' is created. Its root dentry is
-       'a'.  'C' is mounted on mount 'B' at dentry 'b'. Also 'C' is set as a
-       slave mount of 'Z'. In other words 'A' and 'C' are both slave mounts of
-       'Z'.  All mount/unmount events on 'Z' propagates to 'A' and 'C'. But
-       mount/unmount on 'A' do not propagate anywhere else. Similarly
-       mount/unmount on 'C' do not propagate anywhere else.
-
-       8. 'A' is a unbindable mount and 'B' is a non-shared mount. This is a
-       invalid operation. A unbindable mount cannot be bind mounted.
-
-5c) Rbind semantics
-
-       rbind is same as bind. Bind replicates the specified mount.  Rbind
-       replicates all the mounts in the tree belonging to the specified mount.
-       Rbind mount is bind mount applied to all the mounts in the tree.
-
-       If the source tree that is rbind has some unbindable mounts,
-       then the subtree under the unbindable mount is pruned in the new
-       location.
-
-       eg: lets say we have the following mount tree.
-
-               A
-             /   \
-             B   C
-            / \ / \
-            D E F G
-
-            Lets say all the mount except the mount C in the tree are
-            of a type other than unbindable.
-
-            If this tree is rbound to say Z
-
-            We will have the following tree at the new location.
-
-               Z
-               |
-               A'
-              /
-             B'                Note how the tree under C is pruned
-            / \                in the new location.
-           D' E'
-
-
-
-5d) Move semantics
-
-       Consider the following command
-
-       mount --move A  B/b
-
-       where 'A' is the source mount, 'B' is the destination mount and 'b' is
-       the dentry in the destination mount.
-
-       The outcome depends on the type of the mount of 'A' and 'B'. The table
-       below is a quick reference.
-   ---------------------------------------------------------------------------
-   |                   MOVE MOUNT OPERATION                                 |
-   |**************************************************************************
-   | source(A)->| shared      |       private  |       slave    | unbindable |
-   | dest(B)  |               |                |                |            |
-   |   |      |               |                |                |            |
-   |   v      |               |                |                |            |
-   |**************************************************************************
-   |  shared  | shared        |     shared     |shared and slave|  invalid   |
-   |          |               |                |                |            |
-   |non-shared| shared        |      private   |    slave       | unbindable |
-   ***************************************************************************
-       NOTE: moving a mount residing under a shared mount is invalid.
-
-      Details follow:
-
-       1. 'A' is a shared mount and 'B' is a shared mount.  The mount 'A' is
-       mounted on mount 'B' at dentry 'b'.  Also new mounts 'A1', 'A2'...'An'
-       are created and mounted at dentry 'b' on all mounts that receive
-       propagation from mount 'B'. A new propagation tree is created in the
-       exact same configuration as that of 'B'. This new propagation tree
-       contains all the new mounts 'A1', 'A2'...  'An'.  And this new
-       propagation tree is appended to the already existing propagation tree
-       of 'A'.
-
-       2. 'A' is a private mount and 'B' is a shared mount. The mount 'A' is
-       mounted on mount 'B' at dentry 'b'. Also new mount 'A1', 'A2'... 'An'
-       are created and mounted at dentry 'b' on all mounts that receive
-       propagation from mount 'B'. The mount 'A' becomes a shared mount and a
-       propagation tree is created which is identical to that of
-       'B'. This new propagation tree contains all the new mounts 'A1',
-       'A2'...  'An'.
-
-       3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount.  The
-       mount 'A' is mounted on mount 'B' at dentry 'b'.  Also new mounts 'A1',
-       'A2'... 'An' are created and mounted at dentry 'b' on all mounts that
-       receive propagation from mount 'B'. A new propagation tree is created
-       in the exact same configuration as that of 'B'. This new propagation
-       tree contains all the new mounts 'A1', 'A2'...  'An'.  And this new
-       propagation tree is appended to the already existing propagation tree of
-       'A'.  Mount 'A' continues to be the slave mount of 'Z' but it also
-       becomes 'shared'.
-
-       4. 'A' is a unbindable mount and 'B' is a shared mount. The operation
-       is invalid. Because mounting anything on the shared mount 'B' can
-       create new mounts that get mounted on the mounts that receive
-       propagation from 'B'.  And since the mount 'A' is unbindable, cloning
-       it to mount at other mountpoints is not possible.
-
-       5. 'A' is a private mount and 'B' is a non-shared(private or slave or
-       unbindable) mount. The mount 'A' is mounted on mount 'B' at dentry 'b'.
-
-       6. 'A' is a shared mount and 'B' is a non-shared mount.  The mount 'A'
-       is mounted on mount 'B' at dentry 'b'.  Mount 'A' continues to be a
-       shared mount.
-
-       7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount.
-       The mount 'A' is mounted on mount 'B' at dentry 'b'.  Mount 'A'
-       continues to be a slave mount of mount 'Z'.
-
-       8. 'A' is a unbindable mount and 'B' is a non-shared mount. The mount
-       'A' is mounted on mount 'B' at dentry 'b'. Mount 'A' continues to be a
-       unbindable mount.
-
-5e) Mount semantics
-
-       Consider the following command
-
-       mount device  B/b
-
-       'B' is the destination mount and 'b' is the dentry in the destination
-       mount.
-
-       The above operation is the same as bind operation with the exception
-       that the source mount is always a private mount.
-
-
-5f) Unmount semantics
-
-       Consider the following command
-
-       umount A
-
-       where 'A' is a mount mounted on mount 'B' at dentry 'b'.
-
-       If mount 'B' is shared, then all most-recently-mounted mounts at dentry
-       'b' on mounts that receive propagation from mount 'B' and does not have
-       sub-mounts within them are unmounted.
-
-       Example: Lets say 'B1', 'B2', 'B3' are shared mounts that propagate to
-       each other.
-
-       lets say 'A1', 'A2', 'A3' are first mounted at dentry 'b' on mount
-       'B1', 'B2' and 'B3' respectively.
-
-       lets say 'C1', 'C2', 'C3' are next mounted at the same dentry 'b' on
-       mount 'B1', 'B2' and 'B3' respectively.
-
-       if 'C1' is unmounted, all the mounts that are most-recently-mounted on
-       'B1' and on the mounts that 'B1' propagates-to are unmounted.
-
-       'B1' propagates to 'B2' and 'B3'. And the most recently mounted mount
-       on 'B2' at dentry 'b' is 'C2', and that of mount 'B3' is 'C3'.
-
-       So all 'C1', 'C2' and 'C3' should be unmounted.
-
-       If any of 'C2' or 'C3' has some child mounts, then that mount is not
-       unmounted, but all other mounts are unmounted. However if 'C1' is told
-       to be unmounted and 'C1' has some sub-mounts, the umount operation is
-       failed entirely.
-
-5g) Clone Namespace
-
-       A cloned namespace contains all the mounts as that of the parent
-       namespace.
-
-       Lets say 'A' and 'B' are the corresponding mounts in the parent and the
-       child namespace.
-
-       If 'A' is shared, then 'B' is also shared and 'A' and 'B' propagate to
-       each other.
-
-       If 'A' is a slave mount of 'Z', then 'B' is also the slave mount of
-       'Z'.
-
-       If 'A' is a private mount, then 'B' is a private mount too.
-
-       If 'A' is unbindable mount, then 'B' is a unbindable mount too.
-
-
-6) Quiz
-
-       A. What is the result of the following command sequence?
-
-               mount --bind /mnt /mnt
-               mount --make-shared /mnt
-               mount --bind /mnt /tmp
-               mount --move /tmp /mnt/1
-
-               what should be the contents of /mnt /mnt/1 /mnt/1/1 should be?
-               Should they all be identical? or should /mnt and /mnt/1 be
-               identical only?
-
-
-       B. What is the result of the following command sequence?
-
-               mount --make-rshared /
-               mkdir -p /v/1
-               mount --rbind / /v/1
-
-               what should be the content of /v/1/v/1 be?
-
-
-       C. What is the result of the following command sequence?
-
-               mount --bind /mnt /mnt
-               mount --make-shared /mnt
-               mkdir -p /mnt/1/2/3 /mnt/1/test
-               mount --bind /mnt/1 /tmp
-               mount --make-slave /mnt
-               mount --make-shared /mnt
-               mount --bind /mnt/1/2 /tmp1
-               mount --make-slave /mnt
-
-               At this point we have the first mount at /tmp and
-               its root dentry is 1. Lets call this mount 'A'
-               And then we have a second mount at /tmp1 with root
-               dentry 2. Lets call this mount 'B'
-               Next we have a third mount at /mnt with root dentry
-               mnt. Lets call this mount 'C'
-
-               'B' is the slave of 'A' and 'C' is a slave of 'B'
-               A -> B -> C
-
-               at this point if we execute the following command
-
-               mount --bind /bin /tmp/test
-
-               The mount is attempted on 'A'
-
-               will the mount propagate to 'B' and 'C' ?
-
-               what would be the contents of
-               /mnt/1/test be?
-
-7) FAQ
-
-       Q1. Why is bind mount needed? How is it different from symbolic links?
-               symbolic links can get stale if the destination mount gets
-               unmounted or moved. Bind mounts continue to exist even if the
-               other mount is unmounted or moved.
-
-       Q2. Why can't the shared subtree be implemented using exportfs?
-
-               exportfs is a heavyweight way of accomplishing part of what
-               shared subtree can do. I cannot imagine a way to implement the
-               semantics of slave mount using exportfs?
-
-       Q3 Why is unbindable mount needed?
-
-               Lets say we want to replicate the mount tree at multiple
-               locations within the same subtree.
-
-               if one rbind mounts a tree within the same subtree 'n' times
-               the number of mounts created is an exponential function of 'n'.
-               Having unbindable mount can help prune the unneeded bind
-               mounts. Here is a example.
-
-               step 1:
-                  lets say the root tree has just two directories with
-                  one vfsmount.
-                                   root
-                                  /    \
-                                 tmp    usr
-
-                   And we want to replicate the tree at multiple
-                   mountpoints under /root/tmp
-
-               step2:
-                     mount --make-shared /root
-
-                     mkdir -p /tmp/m1
-
-                     mount --rbind /root /tmp/m1
-
-                     the new tree now looks like this:
-
-                                   root
-                                  /    \
-                                tmp    usr
-                               /
-                              m1
-                             /  \
-                            tmp  usr
-                            /
-                           m1
-
-                         it has two vfsmounts
-
-               step3:
-                           mkdir -p /tmp/m2
-                           mount --rbind /root /tmp/m2
-
-                       the new tree now looks like this:
-
-                                     root
-                                    /    \
-                                  tmp     usr
-                                 /    \
-                               m1       m2
-                              / \       /  \
-                            tmp  usr   tmp  usr
-                            / \          /
-                           m1  m2      m1
-                               / \     /  \
-                             tmp usr  tmp   usr
-                             /        / \
-                            m1       m1  m2
-                           /  \
-                         tmp   usr
-                         /  \
-                        m1   m2
-
-                      it has 6 vfsmounts
-
-               step 4:
-                         mkdir -p /tmp/m3
-                         mount --rbind /root /tmp/m3
-
-                         I wont' draw the tree..but it has 24 vfsmounts
-
-
-               at step i the number of vfsmounts is V[i] = i*V[i-1].
-               This is an exponential function. And this tree has way more
-               mounts than what we really needed in the first place.
-
-               One could use a series of umount at each step to prune
-               out the unneeded mounts. But there is a better solution.
-               Unclonable mounts come in handy here.
-
-               step 1:
-                  lets say the root tree has just two directories with
-                  one vfsmount.
-                                   root
-                                  /    \
-                                 tmp    usr
-
-                   How do we set up the same tree at multiple locations under
-                   /root/tmp
-
-               step2:
-                     mount --bind /root/tmp /root/tmp
-
-                     mount --make-rshared /root
-                     mount --make-unbindable /root/tmp
-
-                     mkdir -p /tmp/m1
-
-                     mount --rbind /root /tmp/m1
-
-                     the new tree now looks like this:
-
-                                   root
-                                  /    \
-                                tmp    usr
-                               /
-                              m1
-                             /  \
-                            tmp  usr
-
-               step3:
-                           mkdir -p /tmp/m2
-                           mount --rbind /root /tmp/m2
-
-                     the new tree now looks like this:
-
-                                   root
-                                  /    \
-                                tmp    usr
-                               /   \
-                              m1     m2
-                             /  \     / \
-                            tmp  usr tmp usr
-
-               step4:
-
-                           mkdir -p /tmp/m3
-                           mount --rbind /root /tmp/m3
-
-                     the new tree now looks like this:
-
-                                         root
-                                     /           \
-                                    tmp           usr
-                                /    \    \
-                              m1     m2     m3
-                             /  \     / \    /  \
-                            tmp  usr tmp usr tmp usr
-
-8) Implementation
-
-8A) Datastructure
-
-       4 new fields are introduced to struct vfsmount
-       ->mnt_share
-       ->mnt_slave_list
-       ->mnt_slave
-       ->mnt_master
-
-       ->mnt_share links together all the mount to/from which this vfsmount
-               send/receives propagation events.
-
-       ->mnt_slave_list links all the mounts to which this vfsmount propagates
-               to.
-
-       ->mnt_slave links together all the slaves that its master vfsmount
-               propagates to.
-
-       ->mnt_master points to the master vfsmount from which this vfsmount
-               receives propagation.
-
-       ->mnt_flags takes two more flags to indicate the propagation status of
-               the vfsmount.  MNT_SHARE indicates that the vfsmount is a shared
-               vfsmount.  MNT_UNCLONABLE indicates that the vfsmount cannot be
-               replicated.
-
-       All the shared vfsmounts in a peer group form a cyclic list through
-       ->mnt_share.
-
-       All vfsmounts with the same ->mnt_master form on a cyclic list anchored
-       in ->mnt_master->mnt_slave_list and going through ->mnt_slave.
-
-        ->mnt_master can point to arbitrary (and possibly different) members
-        of master peer group.  To find all immediate slaves of a peer group
-        you need to go through _all_ ->mnt_slave_list of its members.
-        Conceptually it's just a single set - distribution among the
-        individual lists does not affect propagation or the way propagation
-        tree is modified by operations.
-
-       A example propagation tree looks as shown in the figure below.
-       [ NOTE: Though it looks like a forest, if we consider all the shared
-       mounts as a conceptual entity called 'pnode', it becomes a tree]
-
-
-                       A <--> B <--> C <---> D
-                      /|\            /|      |\
-                     / F G          J K      H I
-                    /
-                   E<-->K
-                       /|\
-                      M L N
-
-       In the above figure  A,B,C and D all are shared and propagate to each
-       other.   'A' has got 3 slave mounts 'E' 'F' and 'G' 'C' has got 2 slave
-       mounts 'J' and 'K'  and  'D' has got two slave mounts 'H' and 'I'.
-       'E' is also shared with 'K' and they propagate to each other.  And
-       'K' has 3 slaves 'M', 'L' and 'N'
-
-       A's ->mnt_share links with the ->mnt_share of 'B' 'C' and 'D'
-
-       A's ->mnt_slave_list links with ->mnt_slave of 'E', 'K', 'F' and 'G'
-
-       E's ->mnt_share links with ->mnt_share of K
-       'E', 'K', 'F', 'G' have their ->mnt_master point to struct
-                               vfsmount of 'A'
-       'M', 'L', 'N' have their ->mnt_master point to struct vfsmount of 'K'
-       K's ->mnt_slave_list links with ->mnt_slave of 'M', 'L' and 'N'
-
-       C's ->mnt_slave_list links with ->mnt_slave of 'J' and 'K'
-       J and K's ->mnt_master points to struct vfsmount of C
-       and finally D's ->mnt_slave_list links with ->mnt_slave of 'H' and 'I'
-       'H' and 'I' have their ->mnt_master pointing to struct vfsmount of 'D'.
-
-
-       NOTE: The propagation tree is orthogonal to the mount tree.
-
-
-8B Algorithm:
-
-       The crux of the implementation resides in rbind/move operation.
-
-       The overall algorithm breaks the operation into 3 phases: (look at
-       attach_recursive_mnt() and propagate_mnt())
-
-       1. prepare phase.
-       2. commit phases.
-       3. abort phases.
-
-       Prepare phase:
-
-       for each mount in the source tree:
-                  a) Create the necessary number of mount trees to
-                       be attached to each of the mounts that receive
-                       propagation from the destination mount.
-                  b) Do not attach any of the trees to its destination.
-                     However note down its ->mnt_parent and ->mnt_mountpoint
-                  c) Link all the new mounts to form a propagation tree that
-                     is identical to the propagation tree of the destination
-                     mount.
-
-                  If this phase is successful, there should be 'n' new
-                  propagation trees; where 'n' is the number of mounts in the
-                  source tree.  Go to the commit phase
-
-                  Also there should be 'm' new mount trees, where 'm' is
-                  the number of mounts to which the destination mount
-                  propagates to.
-
-                  if any memory allocations fail, go to the abort phase.
-
-       Commit phase
-               attach each of the mount trees to their corresponding
-               destination mounts.
-
-       Abort phase
-               delete all the newly created trees.
-
-       NOTE: all the propagation related functionality resides in the file
-       pnode.c
-
-
-------------------------------------------------------------------------
-
-version 0.1  (created the initial document, Ram Pai linuxram@us.ibm.com)
-version 0.2  (Incorporated comments from Al Viro)
index aa986a35e9945071abed471776565a2cf4644787..f99254327ae59b59971d979b38cc083d3ac096e5 100644 (file)
@@ -23,6 +23,7 @@ Currently, these files are in /proc/sys/fs:
 - inode-max
 - inode-nr
 - inode-state
+- nr_open
 - overflowuid
 - overflowgid
 - suid_dumpable
@@ -91,6 +92,15 @@ usage of file handles and you don't need to increase the maximum.
 
 ==============================================================
 
+nr_open:
+
+This denotes the maximum number of file-handles a process can
+allocate. Default value is 1024*1024 (1048576) which should be
+enough for most machines. Actual limit depends on RLIMIT_NOFILE
+resource limit.
+
+==============================================================
+
 inode-max, inode-nr & inode-state:
 
 As with file handles, the kernel allocates the inode structures
index 24eac1bc735d733df28901555eefe36217d5dd2a..8a4863c4edd4c2463ac7fe5a5a492ac5156c9932 100644 (file)
@@ -32,6 +32,7 @@ Currently, these files are in /proc/sys/vm:
 - min_unmapped_ratio
 - min_slab_ratio
 - panic_on_oom
+- oom_dump_tasks
 - oom_kill_allocating_task
 - mmap_min_address
 - numa_zonelist_order
@@ -232,6 +233,27 @@ according to your policy of failover.
 
 =============================================================
 
+oom_dump_tasks
+
+Enables a system-wide task dump (excluding kernel threads) to be
+produced when the kernel performs an OOM-killing and includes such
+information as pid, uid, tgid, vm size, rss, cpu, oom_adj score, and
+name.  This is helpful to determine why the OOM killer was invoked
+and to identify the rogue task that caused it.
+
+If this is set to zero, this information is suppressed.  On very
+large systems with thousands of tasks it may not be feasible to dump
+the memory state information for each one.  Such systems should not
+be forced to incur a performance penalty in OOM conditions when the
+information may not be desired.
+
+If this is set to non-zero, this information is shown whenever the
+OOM killer actually kills a memory-hogging task.
+
+The default value is 0.
+
+=============================================================
+
 oom_kill_allocating_task
 
 This enables or disables killing the OOM-triggering task in
diff --git a/Documentation/unaligned-memory-access.txt b/Documentation/unaligned-memory-access.txt
new file mode 100644 (file)
index 0000000..6223eac
--- /dev/null
@@ -0,0 +1,226 @@
+UNALIGNED MEMORY ACCESSES
+=========================
+
+Linux runs on a wide variety of architectures which have varying behaviour
+when it comes to memory access. This document presents some details about
+unaligned accesses, why you need to write code that doesn't cause them,
+and how to write such code!
+
+
+The definition of an unaligned access
+=====================================
+
+Unaligned memory accesses occur when you try to read N bytes of data starting
+from an address that is not evenly divisible by N (i.e. addr % N != 0).
+For example, reading 4 bytes of data from address 0x10004 is fine, but
+reading 4 bytes of data from address 0x10005 would be an unaligned memory
+access.
+
+The above may seem a little vague, as memory access can happen in different
+ways. The context here is at the machine code level: certain instructions read
+or write a number of bytes to or from memory (e.g. movb, movw, movl in x86
+assembly). As will become clear, it is relatively easy to spot C statements
+which will compile to multiple-byte memory access instructions, namely when
+dealing with types such as u16, u32 and u64.
+
+
+Natural alignment
+=================
+
+The rule mentioned above forms what we refer to as natural alignment:
+When accessing N bytes of memory, the base memory address must be evenly
+divisible by N, i.e. addr % N == 0.
+
+When writing code, assume the target architecture has natural alignment
+requirements.
+
+In reality, only a few architectures require natural alignment on all sizes
+of memory access. However, we must consider ALL supported architectures;
+writing code that satisfies natural alignment requirements is the easiest way
+to achieve full portability.
+
+
+Why unaligned access is bad
+===========================
+
+The effects of performing an unaligned memory access vary from architecture
+to architecture. It would be easy to write a whole document on the differences
+here; a summary of the common scenarios is presented below:
+
+ - Some architectures are able to perform unaligned memory accesses
+   transparently, but there is usually a significant performance cost.
+ - Some architectures raise processor exceptions when unaligned accesses
+   happen. The exception handler is able to correct the unaligned access,
+   at significant cost to performance.
+ - Some architectures raise processor exceptions when unaligned accesses
+   happen, but the exceptions do not contain enough information for the
+   unaligned access to be corrected.
+ - Some architectures are not capable of unaligned memory access, but will
+   silently perform a different memory access to the one that was requested,
+   resulting a a subtle code bug that is hard to detect!
+
+It should be obvious from the above that if your code causes unaligned
+memory accesses to happen, your code will not work correctly on certain
+platforms and will cause performance problems on others.
+
+
+Code that does not cause unaligned access
+=========================================
+
+At first, the concepts above may seem a little hard to relate to actual
+coding practice. After all, you don't have a great deal of control over
+memory addresses of certain variables, etc.
+
+Fortunately things are not too complex, as in most cases, the compiler
+ensures that things will work for you. For example, take the following
+structure:
+
+       struct foo {
+               u16 field1;
+               u32 field2;
+               u8 field3;
+       };
+
+Let us assume that an instance of the above structure resides in memory
+starting at address 0x10000. With a basic level of understanding, it would
+not be unreasonable to expect that accessing field2 would cause an unaligned
+access. You'd be expecting field2 to be located at offset 2 bytes into the
+structure, i.e. address 0x10002, but that address is not evenly divisible
+by 4 (remember, we're reading a 4 byte value here).
+
+Fortunately, the compiler understands the alignment constraints, so in the
+above case it would insert 2 bytes of padding in between field1 and field2.
+Therefore, for standard structure types you can always rely on the compiler
+to pad structures so that accesses to fields are suitably aligned (assuming
+you do not cast the field to a type of different length).
+
+Similarly, you can also rely on the compiler to align variables and function
+parameters to a naturally aligned scheme, based on the size of the type of
+the variable.
+
+At this point, it should be clear that accessing a single byte (u8 or char)
+will never cause an unaligned access, because all memory addresses are evenly
+divisible by one.
+
+On a related topic, with the above considerations in mind you may observe
+that you could reorder the fields in the structure in order to place fields
+where padding would otherwise be inserted, and hence reduce the overall
+resident memory size of structure instances. The optimal layout of the
+above example is:
+
+       struct foo {
+               u32 field2;
+               u16 field1;
+               u8 field3;
+       };
+
+For a natural alignment scheme, the compiler would only have to add a single
+byte of padding at the end of the structure. This padding is added in order
+to satisfy alignment constraints for arrays of these structures.
+
+Another point worth mentioning is the use of __attribute__((packed)) on a
+structure type. This GCC-specific attribute tells the compiler never to
+insert any padding within structures, useful when you want to use a C struct
+to represent some data that comes in a fixed arrangement 'off the wire'.
+
+You might be inclined to believe that usage of this attribute can easily
+lead to unaligned accesses when accessing fields that do not satisfy
+architectural alignment requirements. However, again, the compiler is aware
+of the alignment constraints and will generate extra instructions to perform
+the memory access in a way that does not cause unaligned access. Of course,
+the extra instructions obviously cause a loss in performance compared to the
+non-packed case, so the packed attribute should only be used when avoiding
+structure padding is of importance.
+
+
+Code that causes unaligned access
+=================================
+
+With the above in mind, let's move onto a real life example of a function
+that can cause an unaligned memory access. The following function adapted
+from include/linux/etherdevice.h is an optimized routine to compare two
+ethernet MAC addresses for equality.
+
+unsigned int compare_ether_addr(const u8 *addr1, const u8 *addr2)
+{
+       const u16 *a = (const u16 *) addr1;
+       const u16 *b = (const u16 *) addr2;
+       return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
+}
+
+In the above function, the reference to a[0] causes 2 bytes (16 bits) to
+be read from memory starting at address addr1. Think about what would happen
+if addr1 was an odd address such as 0x10003. (Hint: it'd be an unaligned
+access.)
+
+Despite the potential unaligned access problems with the above function, it
+is included in the kernel anyway but is understood to only work on
+16-bit-aligned addresses. It is up to the caller to ensure this alignment or
+not use this function at all. This alignment-unsafe function is still useful
+as it is a decent optimization for the cases when you can ensure alignment,
+which is true almost all of the time in ethernet networking context.
+
+
+Here is another example of some code that could cause unaligned accesses:
+       void myfunc(u8 *data, u32 value)
+       {
+               [...]
+               *((u32 *) data) = cpu_to_le32(value);
+               [...]
+       }
+
+This code will cause unaligned accesses every time the data parameter points
+to an address that is not evenly divisible by 4.
+
+In summary, the 2 main scenarios where you may run into unaligned access
+problems involve:
+ 1. Casting variables to types of different lengths
+ 2. Pointer arithmetic followed by access to at least 2 bytes of data
+
+
+Avoiding unaligned accesses
+===========================
+
+The easiest way to avoid unaligned access is to use the get_unaligned() and
+put_unaligned() macros provided by the <asm/unaligned.h> header file.
+
+Going back to an earlier example of code that potentially causes unaligned
+access:
+
+       void myfunc(u8 *data, u32 value)
+       {
+               [...]
+               *((u32 *) data) = cpu_to_le32(value);
+               [...]
+       }
+
+To avoid the unaligned memory access, you would rewrite it as follows:
+
+       void myfunc(u8 *data, u32 value)
+       {
+               [...]
+               value = cpu_to_le32(value);
+               put_unaligned(value, (u32 *) data);
+               [...]
+       }
+
+The get_unaligned() macro works similarly. Assuming 'data' is a pointer to
+memory and you wish to avoid unaligned access, its usage is as follows:
+
+       u32 value = get_unaligned((u32 *) data);
+
+These macros work work for memory accesses of any length (not just 32 bits as
+in the examples above). Be aware that when compared to standard access of
+aligned memory, using these macros to access unaligned memory can be costly in
+terms of performance.
+
+If use of such macros is not convenient, another option is to use memcpy(),
+where the source or destination (or both) are of type u8* or unsigned char*.
+Due to the byte-wise nature of this operation, unaligned accesses are avoided.
+
+--
+Author: Daniel Drake <dsd@gentoo.org>
+With help from: Alan Cox, Avuton Olrich, Heikki Orsila, Jan Engelhardt,
+Johannes Berg, Kyle McMartin, Kyle Moffett, Randy Dunlap, Robert Hancock,
+Uli Kunitz, Vadim Lobanov
+
index 752613c4cea2b5e7951b8cd661996745c2b0a1c4..7b0ceaaad7af916ab0ed24d2e8ed05738bd830e0 100644 (file)
@@ -4,3 +4,5 @@ ds2482
        - The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses.
 ds2490
        - The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges.
+w1-gpio
+       - GPIO 1-wire bus master driver.
diff --git a/Documentation/w1/masters/w1-gpio b/Documentation/w1/masters/w1-gpio
new file mode 100644 (file)
index 0000000..af5d3b4
--- /dev/null
@@ -0,0 +1,33 @@
+Kernel driver w1-gpio
+=====================
+
+Author: Ville Syrjala <syrjala@sci.fi>
+
+
+Description
+-----------
+
+GPIO 1-wire bus master driver. The driver uses the GPIO API to control the
+wire and the GPIO pin can be specified using platform data.
+
+
+Example (mach-at91)
+-------------------
+
+#include <linux/w1-gpio.h>
+
+static struct w1_gpio_platform_data foo_w1_gpio_pdata = {
+       .pin            = AT91_PIN_PB20,
+       .is_open_drain  = 1,
+};
+
+static struct platform_device foo_w1_device = {
+       .name                   = "w1-gpio",
+       .id                     = -1,
+       .dev.platform_data      = &foo_w1_gpio_pdata,
+};
+
+...
+       at91_set_GPIO_periph(foo_w1_gpio_pdata.pin, 1);
+       at91_set_multi_drive(foo_w1_gpio_pdata.pin, 1);
+       platform_device_register(&foo_w1_device);
index 4f3da8b56979c5365ab8403a90eaebd3ec3a378b..a372c86fd07bc338861b1ff316a8a54229f9ef67 100644 (file)
@@ -338,13 +338,12 @@ S:        Maintained for 2.4; PCI support for 2.6.
 AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
 P:     Thomas Dahlmann
 M:     thomas.dahlmann@amd.com
-L:     info-linux@geode.amd.com
+L:     info-linux@geode.amd.com        (subscribers-only)
 S:     Supported
 
 AMD GEODE PROCESSOR/CHIPSET SUPPORT
 P:     Jordan Crouse
-M:     info-linux@geode.amd.com
-L:     info-linux@geode.amd.com
+L:     info-linux@geode.amd.com        (subscribers-only)
 W:     http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
 S:     Supported
 
@@ -841,6 +840,12 @@ L: linux-kernel@vger.kernel.org
 T:     git kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
 S:     Maintained
 
+BLOCK2MTD DRIVER
+P:     Joern Engel
+M:     joern@lazybastard.org
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+
 BLUETOOTH SUBSYSTEM
 P:     Marcel Holtmann
 M:     marcel@holtmann.org
@@ -1366,6 +1371,11 @@ W:       http://linuxtv.org/
 T:     git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git
 S:     Maintained
 
+DZ DECSTATION DZ11 SERIAL DRIVER
+P:     Maciej W. Rozycki
+M:     macro@linux-mips.org
+S:     Maintained
+
 EATA-DMA SCSI DRIVER
 P:     Michael Neuffer
 L:     linux-eata@i-connect.net, linux-scsi@vger.kernel.org
@@ -3031,8 +3041,8 @@ L:        linux-abi-devel@lists.sourceforge.net
 S:     Maintained
 
 PHRAM MTD DRIVER
-P:     Jörn Engel
-M:     joern@wh.fh-wedel.de
+P:     Joern Engel
+M:     joern@lazybastard.org
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
 
@@ -3219,6 +3229,12 @@ M:       mporter@kernel.crashing.org
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+RDC R-321X SoC
+P:     Florian Fainelli
+M:     florian.fainelli@telecomint.eu
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+
 RDC R6040 FAST ETHERNET DRIVER
 P:     Florian Fainelli
 M:     florian.fainelli@telecomint.eu
@@ -3856,6 +3872,12 @@ M:       oliver@neukum.name
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 
+USB AUERSWALD DRIVER
+P:     Wolfgang Muees
+M:     wolfgang@iksw-muees.de
+L:      linux-usb@vger.kernel.org
+S:     Maintained
+
 USB BLOCK DRIVER (UB ub)
 P:     Pete Zaitcev
 M:     zaitcev@redhat.com
@@ -4006,12 +4028,6 @@ S:       Maintained
 W:     http://geocities.com/i0xox0i
 W:     http://firstlight.net/cvs
 
-USB AUERSWALD DRIVER
-P:     Wolfgang Muees
-M:     wolfgang@iksw-muees.de
-L:      linux-usb@vger.kernel.org
-S:     Maintained
-
 USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER
 P:     Gary Brubaker
 M:     xavyer@ix.netcom.com
index ac02e42a2627f359575ae0e689afca911a75e0ff..ab0c56630a8cb5924813a196b1b2be763f51d5b6 100644 (file)
@@ -10,11 +10,12 @@ bug report. This explains what you should do with the "Oops" information
 to make it useful to the recipient.
 
       Send the output to the maintainer of the kernel area that seems to
-be involved with the problem. Don't worry too much about getting the
-wrong person. If you are unsure send it to the person responsible for the
-code relevant to what you were doing. If it occurs repeatably try and
-describe how to recreate it. That is worth even more than the oops itself.
-The list of maintainers is in the MAINTAINERS file in this directory.
+be involved with the problem, and cc the relevant mailing list. Don't
+worry too much about getting the wrong person. If you are unsure send it
+to the person responsible for the code relevant to what you were doing.
+If it occurs repeatably try and describe how to recreate it. That is
+worth even more than the oops itself.  The list of maintainers and
+mailing lists is in the MAINTAINERS file in this directory.
 
       If it is a security bug, please copy the Security Contact listed
 in the MAINTAINERS file.  They can help coordinate bugfix and disclosure.
index f45f28cc10da94e24c4add02315f950f9787ec37..3f6265f2d9d4749a032bb28e325622bc92d81a1f 100644 (file)
@@ -7,15 +7,6 @@ config EARLY_PRINTK
        depends on ALPHA_GENERIC || ALPHA_SRM
        default y
 
-config DEBUG_RWLOCK
-       bool "Read-write spinlock debugging"
-       depends on DEBUG_KERNEL
-       help
-         If you say Y here then read-write lock processing will count how many
-         times it has tried to get the lock and issue an error message after
-         too many attempts.  If you suspect a rwlock problem or a kernel
-         hacker asks for this option then say Y.  Otherwise say N.
-
 config ALPHA_LEGACY_START_ADDRESS
        bool "Legacy kernel start address"
        depends on ALPHA_GENERIC
index 6da9c3dbde448fd38f737560bb919f0eb8186022..e43f68fd66b0d5fae206f3935492938f33e48941 100644 (file)
@@ -882,7 +882,6 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_SPINLOCK is not set
 CONFIG_DEBUG_INFO=y
 CONFIG_EARLY_PRINTK=y
-# CONFIG_DEBUG_RWLOCK is not set
 # CONFIG_DEBUG_SEMAPHORE is not set
 CONFIG_ALPHA_LEGACY_START_ADDRESS=y
 CONFIG_MATHEMU=y
index e4a0bcf1d28b6834492808c0cf52b4681e3b0182..a872078497be7382d37b3326597bf967708ad4a5 100644 (file)
@@ -241,7 +241,8 @@ albacore_init_arch(void)
                                       size / 1024);
                }
 #endif
-               reserve_bootmem_node(NODE_DATA(0), pci_mem, memtop - pci_mem);
+               reserve_bootmem_node(NODE_DATA(0), pci_mem, memtop -
+                               pci_mem, BOOTMEM_DEFAULT);
                printk("irongate_init_arch: temporarily reserving "
                        "region %08lx-%08lx for PCI\n", pci_mem, memtop - 1);
        }
index 6413c5f232264dbc9b165489396dbb6987d42351..72f9a619a66d8055b03df676979b0645879c7160 100644 (file)
@@ -430,7 +430,7 @@ sys_getpagesize(void)
 asmlinkage unsigned long
 sys_getdtablesize(void)
 {
-       return NR_OPEN;
+       return sysctl_nr_open;
 }
 
 /*
index beff6297f788a029aa7423bc2a615915a764126d..74c3466256586800730be7e19c94421a2050b877 100644 (file)
@@ -428,7 +428,8 @@ setup_memory(void *kernel_end)
        }
 
        /* Reserve the bootmap memory.  */
-       reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size);
+       reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size,
+                       BOOTMEM_DEFAULT);
        printk("reserving pages %ld:%ld\n", bootmap_start, bootmap_start+PFN_UP(bootmap_size));
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -446,7 +447,7 @@ setup_memory(void *kernel_end)
                                       phys_to_virt(PFN_PHYS(max_low_pfn)));
                } else {
                        reserve_bootmem(virt_to_phys((void *)initrd_start),
-                                       INITRD_SIZE);
+                                       INITRD_SIZE, BOOTMEM_DEFAULT);
                }
        }
 #endif /* CONFIG_BLK_DEV_INITRD */
index f4ab233201b296013c7c45511a953838d29226d8..63c2073401ee5ce9bf75cbe90f28bffb88cc8375 100644 (file)
@@ -77,10 +77,6 @@ int smp_num_probed;          /* Internal processor count */
 int smp_num_cpus = 1;          /* Number that came online.  */
 EXPORT_SYMBOL(smp_num_cpus);
 
-extern void calibrate_delay(void);
-
-\f
-
 /*
  * Called by both boot and secondaries to move global data into
  *  per-processor storage.
index e3e3806a6f254f02b3cec0d1a02fba5fc05639c2..10ab7833e83ca660c7292869e501434251e4bdba 100644 (file)
@@ -242,7 +242,8 @@ setup_memory_node(int nid, void *kernel_end)
        }
 
        /* Reserve the bootmap memory.  */
-       reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(bootmap_start), bootmap_size);
+       reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(bootmap_start),
+                       bootmap_size, BOOTMEM_DEFAULT);
        printk(" reserving pages %ld:%ld\n", bootmap_start, bootmap_start+PFN_UP(bootmap_size));
 
        node_set_online(nid);
@@ -281,7 +282,7 @@ setup_memory(void *kernel_end)
                        nid = kvaddr_to_nid(initrd_start);
                        reserve_bootmem_node(NODE_DATA(nid),
                                             virt_to_phys((void *)initrd_start),
-                                            INITRD_SIZE);
+                                            INITRD_SIZE, BOOTMEM_DEFAULT);
                }
        }
 #endif /* CONFIG_BLK_DEV_INITRD */
index aa29ea58ca09ee9b99286b78a022264d800c71bc..0ce38dfa6ebe3cdc1e3140a9cc030b99707feb24 100644 (file)
@@ -383,6 +383,7 @@ static void at91_lcdc_tft_power_control(int on)
 }
 
 static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+       .lcdcon_is_backlight            = true,
        .default_bpp                    = 16,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
        .default_lcdcon2                = AT91SAM9261_DEFAULT_TFT_LCDCON2,
index f09347a86e7116c31d59c43468b1b749b8adba85..38313abef657d0a01684634c3aaf43eba6e82c2b 100644 (file)
@@ -253,6 +253,7 @@ static void at91_lcdc_power_control(int on)
 
 /* Driver datas */
 static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+       .lcdcon_is_backlight            = true,
        .default_bpp                    = 16,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
        .default_lcdcon2                = AT91SAM9263_DEFAULT_LCDCON2,
index a454451c97c36ea77ee9abb2a74e6b9f99ff0f6e..eca558c6bf5d1d121b18e89e68279c3f99c0706b 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/serial_8250.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 
 #include <asm/elf.h>
 #include <asm/io.h>
index c0ad7c0fbae0c83f74906bc08f0f09d4e2e59731..ec00f26bffa4825c5ee61bf6c4f635f992550949 100644 (file)
@@ -239,7 +239,7 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
         * Reserve the bootmem bitmap for this node.
         */
        reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT,
-                            boot_pages << PAGE_SHIFT);
+                            boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /*
@@ -247,7 +247,7 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
         */
        if (node == initrd_node) {
                reserve_bootmem_node(pgdat, phys_initrd_start,
-                                    phys_initrd_size);
+                                    phys_initrd_size, BOOTMEM_DEFAULT);
                initrd_start = __phys_to_virt(phys_initrd_start);
                initrd_end = initrd_start + phys_initrd_size;
        }
index e5d61ee3d4a1bec9c309f3ba7b91de8ce4f9cb53..d41a75ed3dce27431fd11c78f7cf27553bbbe61c 100644 (file)
@@ -605,9 +605,11 @@ void __init reserve_node_zero(pg_data_t *pgdat)
         * Note that this can only be in node 0.
         */
 #ifdef CONFIG_XIP_KERNEL
-       reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
+       reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start,
+                       BOOTMEM_DEFAULT);
 #else
-       reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
+       reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext,
+                       BOOTMEM_DEFAULT);
 #endif
 
        /*
@@ -615,7 +617,7 @@ void __init reserve_node_zero(pg_data_t *pgdat)
         * and can only be in node 0.
         */
        reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
-                            PTRS_PER_PGD * sizeof(pgd_t));
+                            PTRS_PER_PGD * sizeof(pgd_t), BOOTMEM_DEFAULT);
 
        /*
         * Hmm... This should go elsewhere, but we really really need to
@@ -638,8 +640,10 @@ void __init reserve_node_zero(pg_data_t *pgdat)
        /* H1940 and RX3715 need to reserve this for suspend */
 
        if (machine_is_h1940() || machine_is_rx3715()) {
-               reserve_bootmem_node(pgdat, 0x30003000, 0x1000);
-               reserve_bootmem_node(pgdat, 0x30081000, 0x1000);
+               reserve_bootmem_node(pgdat, 0x30003000, 0x1000,
+                               BOOTMEM_DEFAULT);
+               reserve_bootmem_node(pgdat, 0x30081000, 0x1000,
+                               BOOTMEM_DEFAULT);
        }
 
 #ifdef CONFIG_SA1111
@@ -650,7 +654,8 @@ void __init reserve_node_zero(pg_data_t *pgdat)
        res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
 #endif
        if (res_size)
-               reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);
+               reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size,
+                               BOOTMEM_DEFAULT);
 }
 
 /*
index 8cd3a60954f0e78c53d4e0efb5eec7f5f6272e88..63c62fdea52115e168751c5efa5eec96c7602341 100644 (file)
@@ -27,9 +27,11 @@ void __init reserve_node_zero(pg_data_t *pgdat)
         * Note that this can only be in node 0.
         */
 #ifdef CONFIG_XIP_KERNEL
-       reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
+       reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start,
+                       BOOTMEM_DEFAULT);
 #else
-       reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
+       reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext,
+                       BOOTMEM_DEFAULT);
 #endif
 
        /*
@@ -37,7 +39,8 @@ void __init reserve_node_zero(pg_data_t *pgdat)
         * some architectures which the DRAM is the exception vector to trap,
         * alloc_page breaks with error, although it is not NULL, but "0."
         */
-       reserve_bootmem_node(pgdat, CONFIG_VECTORS_BASE, PAGE_SIZE);
+       reserve_bootmem_node(pgdat, CONFIG_VECTORS_BASE, PAGE_SIZE,
+                       BOOTMEM_DEFAULT);
 }
 
 /*
index ee40c1a0b83d6788f24bd66b8530661b357c5b07..7854f19b77cf6588b23762632c4c3efddd9b0ac4 100644 (file)
@@ -207,7 +207,7 @@ void __init omapfb_reserve_sdram(void)
                        return;
                }
                if (rg.paddr)
-                       reserve_bootmem(rg.paddr, rg.size);
+                       reserve_bootmem(rg.paddr, rg.size, BOOTMEM_DEFAULT);
                reserved += rg.size;
                omapfb_config.mem_desc.region[i] = rg;
                configured_regions++;
index 4b4c1884e1c5a4c7546eebf9ee39dcdf500e9781..e66a07a928cd6f7e10cb4798e61a46de75e492b3 100644 (file)
@@ -489,7 +489,8 @@ static void __init setup_bootmem(void)
                /* Reserve space for the bootmem bitmap... */
                reserve_bootmem_node(NODE_DATA(node),
                                     PFN_PHYS(bootmap_pfn),
-                                    bootmap_size);
+                                    bootmap_size,
+                                    BOOTMEM_DEFAULT);
 
                /* ...and any other reserved regions. */
                for (res = reserved; res; res = res->sibling) {
@@ -505,7 +506,8 @@ static void __init setup_bootmem(void)
                            && res->end < PFN_PHYS(max_pfn))
                                reserve_bootmem_node(
                                        NODE_DATA(node), res->start,
-                                       res->end - res->start + 1);
+                                       res->end - res->start + 1,
+                                       BOOTMEM_DEFAULT);
                }
 
                node_set_online(node);
index b3bc0b56e2c6506849de3ba758aae262f552f477..9aa8800830f396b8ef4fb79a4186b1f9b95dc60a 100644 (file)
 
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/timex.h>
 #include <linux/param.h>
 #include <linux/types.h>
+#include <linux/init.h>
 
 #include <asm/processor.h>
 #include <asm/sysreg.h>
 
-int read_current_timer(unsigned long *timer_value)
+int __devinit read_current_timer(unsigned long *timer_value)
 {
        *timer_value = sysreg_read(COUNT);
        return 0;
index 462cae8937579a0b5207aa54963f2a474aeb1b12..6e106b3d7729f2f8832107babf496d69ed6c4c91 100644 (file)
@@ -406,7 +406,7 @@ void __init setup_arch(char **cmdline_p)
         */
        free_bootmem(memory_start, memory_end - memory_start);
 
-       reserve_bootmem(memory_start, bootmap_size);
+       reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
        /*
         * get kmalloc into gear
         */
index f8c411a24af79e6767c0f834a1daf6d0b4f5f61c..1795aab79064c1ce468cd92d053bc46b0fd7f430 100644 (file)
@@ -37,7 +37,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
index a72c7a620fa1ddbf0dc228e441700aa64f7c156f..97378b0a975308047004fb89eb2768038968597f 100644 (file)
@@ -38,7 +38,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 
 #include <asm/dma.h>
index 21df2f3754975b44ae60746ebe93ddbcfcee7ad6..886f260d9359f35b9e754ecab4eccccbd35ceb94 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index c37dd45c8803fad0817b0eef3e47433e57264a3b..4026c2f3ab4e19e1d9558028b98575bcb7095acc 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index ac52b040b336f13fafee8bda080479880c146b5f..0185350feacc165768899bd959a4cd946549a53b 100644 (file)
@@ -38,7 +38,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index 8703b67d5ec66c95af77c7b2e8773a05fd279041..f7c1f964f13b1a42d38bd14e81dfe5f4c70ca12c 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index 3e52f3f5bd5888b7aa0e0d0c7b10242531a011ec..8a3397db1d212ec35dc10b08d71bc0d1026c494a 100644 (file)
@@ -38,7 +38,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
index b8bbba85af536286e34e6f17cf23e4760e08d70b..d71e0be339212c752a14aeea214ee7d1b72f654f 100644 (file)
@@ -10,7 +10,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb_isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb_sl811.h>
index 772541548b7623d4e0fd2871fe053471559e206c..119e6ea833848a6b8498a48babf1bd668d718d2b 100644 (file)
@@ -38,7 +38,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
index 3a79a9061bdc8309cf6f53e0c3af637068270954..bf9e738a7c6451938a3254039e324c68cc71ff85 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index 7601c3be1b5c3a70256d8d7d3af091261a7a88d6..ed863ce9a2d8c13042160d0cba4d4bc7288f5291 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/spi/spi.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/portmux.h>
index 65466c49d7a99ea35701aaadf1ddb4a6bac7f6b9..4da042e100a0ab3a61b22eb069a8013a04a92b1b 100644 (file)
@@ -137,7 +137,7 @@ setup_arch(char **cmdline_p)
         * Arguments are start, size
          */
 
-        reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size);
+       reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size, BOOTMEM_DEFAULT);
 
        /* paging_init() sets up the MMU and marks all pages as reserved */
 
index a74c08786b21a8500067c2b442cb08b0b2c41daf..6c01464db699419a2b5e8068325c1791ad356188 100644 (file)
@@ -708,7 +708,7 @@ static void __init reserve_dma_coherent(void)
 /*
  * calibrate the delay loop
  */
-void __init calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
 {
        loops_per_jiffy = __delay_loops_MHz * (1000000 / HZ);
 
@@ -925,13 +925,15 @@ static void __init setup_linux_memory(void)
 #endif
 
        /* take back the memory occupied by the kernel image and the bootmem alloc map */
-       reserve_bootmem(kstart, kend - kstart + bootmap_size);
+       reserve_bootmem(kstart, kend - kstart + bootmap_size,
+                       BOOTMEM_DEFAULT);
 
        /* reserve the memory occupied by the initial ramdisk */
 #ifdef CONFIG_BLK_DEV_INITRD
        if (LOADER_TYPE && INITRD_START) {
                if (INITRD_START + INITRD_SIZE <= (low_top_pfn << PAGE_SHIFT)) {
-                       reserve_bootmem(INITRD_START, INITRD_SIZE);
+                       reserve_bootmem(INITRD_START, INITRD_SIZE,
+                                       BOOTMEM_DEFAULT);
                        initrd_start = INITRD_START + PAGE_OFFSET;
                        initrd_end = initrd_start + INITRD_SIZE;
                }
@@ -986,9 +988,10 @@ static void __init setup_uclinux_memory(void)
 
        /* now take back the bits the core kernel is occupying */
 #ifndef CONFIG_PROTECT_KERNEL
-       reserve_bootmem(kend, bootmap_size);
+       reserve_bootmem(kend, bootmap_size, BOOTMEM_DEFAULT);
        reserve_bootmem((unsigned long) &__kernel_image_start,
-                       kend - (unsigned long) &__kernel_image_start);
+                       kend - (unsigned long) &__kernel_image_start,
+                       BOOTMEM_DEFAULT);
 
 #else
        dampr = __get_DAMPR(0);
@@ -996,14 +999,15 @@ static void __init setup_uclinux_memory(void)
        dampr = (dampr >> 4) + 17;
        dampr = 1 << dampr;
 
-       reserve_bootmem(__get_DAMPR(0) & xAMPRx_PPFN, dampr);
+       reserve_bootmem(__get_DAMPR(0) & xAMPRx_PPFN, dampr, BOOTMEM_DEFAULT);
 #endif
 
        /* reserve some memory to do uncached DMA through if requested */
 #ifdef CONFIG_RESERVE_DMA_COHERENT
        if (dma_coherent_mem_start)
                reserve_bootmem(dma_coherent_mem_start,
-                               dma_coherent_mem_end - dma_coherent_mem_start);
+                               dma_coherent_mem_end - dma_coherent_mem_start,
+                               BOOTMEM_DEFAULT);
 #endif
 
 } /* end setup_uclinux_memory() */
index 8dec4dd57b4e06ff44f26da88a0f9d89d8b954da..5a1b4cfea05b37660fbf54d57016bb06e67be6e7 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/random.h>
 #include <linux/bootmem.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include <asm/system.h>
 #include <asm/traps.h>
index b2e86d0255e691e7464bb786e6c16091de0bd84b..cd3734614d9df93cd21787e4adca354ef2a8ecc6 100644 (file)
@@ -173,7 +173,7 @@ void __init setup_arch(char **cmdline_p)
         * the bootmem bitmap so we then reserve it after freeing it :-)
         */
        free_bootmem(memory_start, memory_end - memory_start);
-       reserve_bootmem(memory_start, bootmap_size);
+       reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
        /*
         * get kmalloc into gear
         */
index d6cd45f4c6c79a5f7eebc90ad34f0810e469c72b..0823de1f6ebe2a44fb88dfa8baeac12f278bbfb0 100644 (file)
@@ -129,13 +129,14 @@ void machine_kexec(struct kimage *image)
 
 void arch_crash_save_vmcoreinfo(void)
 {
-#if defined(CONFIG_ARCH_DISCONTIGMEM_ENABLE) && defined(CONFIG_NUMA)
+#if defined(CONFIG_DISCONTIGMEM) || defined(CONFIG_SPARSEMEM)
        VMCOREINFO_SYMBOL(pgdat_list);
        VMCOREINFO_LENGTH(pgdat_list, MAX_NUMNODES);
-
+#endif
+#ifdef CONFIG_NUMA
        VMCOREINFO_SYMBOL(node_memblk);
        VMCOREINFO_LENGTH(node_memblk, NR_NODE_MEMBLKS);
-       VMCOREINFO_SIZE(node_memblk_s);
+       VMCOREINFO_STRUCT_SIZE(node_memblk_s);
        VMCOREINFO_OFFSET(node_memblk_s, start_paddr);
        VMCOREINFO_OFFSET(node_memblk_s, size);
 #endif
index 480b1a5085d542d22618b29a7e763e8f8f3904d6..32ee5979a042c35e120ea1bc9fa0acd49bb411c8 100644 (file)
@@ -120,7 +120,6 @@ static volatile unsigned long go[SLAVE + 1];
 
 #define DEBUG_ITC_SYNC 0
 
-extern void __devinit calibrate_delay (void);
 extern void start_ap (void);
 extern unsigned long ia64_iobase;
 
@@ -477,7 +476,7 @@ start_secondary (void *unused)
        return 0;
 }
 
-struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
+struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
 {
        return NULL;
 }
index 7e9c275ea148579b8b792583f497ae15e21927f3..344f64eca7a983cfe534afd38523ed7597e173f6 100644 (file)
@@ -218,7 +218,7 @@ find_memory (void)
 
        /* Free all available memory, then mark bootmem-map as being in use. */
        efi_memmap_walk(filter_rsvd_memory, free_bootmem);
-       reserve_bootmem(bootmap_start, bootmap_size);
+       reserve_bootmem(bootmap_start, bootmap_size, BOOTMEM_DEFAULT);
 
        find_initrd();
 
index 0b567398f38e0319568c43154f00e9fe2456a344..ee5e68b2af949db34eda7077c43409f35abf2a19 100644 (file)
@@ -299,12 +299,12 @@ static void __init reserve_pernode_space(void)
                pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);
                size = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
                base = __pa(bdp->node_bootmem_map);
-               reserve_bootmem_node(pdp, base, size);
+               reserve_bootmem_node(pdp, base, size, BOOTMEM_DEFAULT);
 
                /* Now the per-node space */
                size = mem_data[node].pernode_size;
                base = __pa(mem_data[node].pernode_addr);
-               reserve_bootmem_node(pdp, base, size);
+               reserve_bootmem_node(pdp, base, size, BOOTMEM_DEFAULT);
        }
 }
 
index ab3eaf85fe4d40d3a273ca101e132574f21e74bf..2c676cc05418a76f60a3d888cad8eb9006347de6 100644 (file)
@@ -100,11 +100,11 @@ u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus)
 static irqreturn_t
 pcibr_error_intr_handler(int irq, void *arg)
 {
-       struct pcibus_info *soft = (struct pcibus_info *)arg;
+       struct pcibus_info *soft = arg;
 
-       if (sal_pcibr_error_interrupt(soft) < 0) {
+       if (sal_pcibr_error_interrupt(soft) < 0)
                panic("pcibr_error_intr_handler(): Fatal Bridge Error");
-       }
+
        return IRQ_HANDLED;
 }
 
index d64814385d705624d504333fe0b204ef63870b43..f1f5db0c40846b3b39e65368996dea3c80a952b7 100644 (file)
@@ -177,25 +177,28 @@ static unsigned long __init setup_memory(void)
         */
        reserve_bootmem(CONFIG_MEMORY_START + PAGE_SIZE,
                (PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE - 1)
-               - CONFIG_MEMORY_START);
+               - CONFIG_MEMORY_START,
+               BOOTMEM_DEFAULT);
 
        /*
         * reserve physical page 0 - it's a special BIOS page on many boxes,
         * enabling clean reboots, SMP operation, laptop functions.
         */
-       reserve_bootmem(CONFIG_MEMORY_START, PAGE_SIZE);
+       reserve_bootmem(CONFIG_MEMORY_START, PAGE_SIZE, BOOTMEM_DEFAULT);
 
        /*
         * reserve memory hole
         */
 #ifdef CONFIG_MEMHOLE
-       reserve_bootmem(CONFIG_MEMHOLE_START, CONFIG_MEMHOLE_SIZE);
+       reserve_bootmem(CONFIG_MEMHOLE_START, CONFIG_MEMHOLE_SIZE,
+                       BOOTMEM_DEFAULT);
 #endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
        if (LOADER_TYPE && INITRD_START) {
                if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
-                       reserve_bootmem(INITRD_START, INITRD_SIZE);
+                       reserve_bootmem(INITRD_START, INITRD_SIZE,
+                                       BOOTMEM_DEFAULT);
                        initrd_start = INITRD_START + PAGE_OFFSET;
                        initrd_end = initrd_start + INITRD_SIZE;
                        printk("initrd:start[%08lx],size[%08lx]\n",
index 0e383da158e95c3a84dfc7ffecb14f94b6325395..2c03ac1d005f44cfe9fe7ad61fa03750e9edf9e9 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/err.h>
 #include <linux/irq.h>
 #include <linux/bootmem.h>
index c7efdb0aefc5998768b0984137b035ce3f1cd7c3..07c1af7dc0e2a3bffec2474e22fab8a17fee0dce 100644 (file)
@@ -91,7 +91,8 @@ unsigned long __init setup_memory(void)
                        PFN_PHYS(mp->pages));
 
                reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(mp->start_pfn),
-                       PFN_PHYS(mp->free_pfn - mp->start_pfn) + bootmap_size);
+                       PFN_PHYS(mp->free_pfn - mp->start_pfn) + bootmap_size,
+                       BOOTMEM_DEFAULT);
 
                if (max_low_pfn < max_pfn)
                        max_low_pfn = max_pfn;
@@ -104,7 +105,7 @@ unsigned long __init setup_memory(void)
        if (LOADER_TYPE && INITRD_START) {
                if (INITRD_START + INITRD_SIZE <= PFN_PHYS(max_low_pfn)) {
                        reserve_bootmem_node(NODE_DATA(0), INITRD_START,
-                               INITRD_SIZE);
+                               INITRD_SIZE, BOOTMEM_DEFAULT);
                        initrd_start = INITRD_START + PAGE_OFFSET;
                        initrd_end = initrd_start + INITRD_SIZE;
                        printk("initrd:start[%08lx],size[%08lx]\n",
index d10726f9038b91606bf894c472703f383a81baf9..cbe36538af47be5cd2914fe7172ad2ea0f96c026 100644 (file)
@@ -32,12 +32,10 @@ void __init amiga_chip_init(void)
     if (!AMIGAHW_PRESENT(CHIP_RAM))
        return;
 
-#ifndef CONFIG_APUS_FAST_EXCEPT
     /*
      *  Remove the first 4 pages where PPC exception handlers will be located
      */
     amiga_chip_size -= 0x4000;
-#endif
     chipram_res.end = amiga_chip_size-1;
     request_resource(&iomem_resource, &chipram_res);
 
index c4a4ffd45bc0feeb68c8f84ff3332e1ac7bc4dd9..343fab49bd9a751435ae710bd4e848c9b6abd6ec 100644 (file)
@@ -84,7 +84,7 @@ unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
 
 static irqreturn_t cia_handler(int irq, void *dev_id)
 {
-       struct ciabase *base = (struct ciabase *)dev_id;
+       struct ciabase *base = dev_id;
        int mach_irq;
        unsigned char ints;
 
index 8dda6515887affd45d33a55981329f5125eda9ba..0055a6c06f755a9aa2ab0f10301782ecf4ab632e 100644 (file)
@@ -154,7 +154,7 @@ void __init atari_stram_reserve_pages(void *start_mem)
        /* always reserve first page of ST-RAM, the first 2 kB are
         * supervisor-only! */
        if (!kernel_in_stram)
-               reserve_bootmem (0, PAGE_SIZE);
+               reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT);
 
 }
 
index ed3a4caec6209dfc5f73b3bf4561b222801d7a6b..9a06c48edcb3c47468a0db8163d116eaaa9d032c 100644 (file)
@@ -323,7 +323,8 @@ void __init setup_arch(char **cmdline_p)
 #ifdef CONFIG_BLK_DEV_INITRD
        if (m68k_ramdisk.size) {
                reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)),
-                                    m68k_ramdisk.addr, m68k_ramdisk.size);
+                                    m68k_ramdisk.addr, m68k_ramdisk.size,
+                                    BOOTMEM_DEFAULT);
                initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
                initrd_end = initrd_start + m68k_ramdisk.size;
                printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
index 81507c53d4a9b7cfce58de6bc0f4ee8f07bbccae..156c6c662c7e87fa3feabf82cc83c6b9c10e6e7e 100644 (file)
@@ -203,7 +203,7 @@ void __init setup_arch(char **cmdline_p)
         * the bootmem bitmap so we then reserve it after freeing it :-)
         */
        free_bootmem(memory_start, memory_end - memory_start);
-       reserve_bootmem(memory_start, bootmap_size);
+       reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
 
        /*
         * Get kmalloc into gear.
index 0d5577569e4c7230b42db6ebcfe7968ce24f6474..b50dbcad47464534688b7414997d488e4ba721bd 100644 (file)
@@ -1,6 +1,5 @@
 
 #include <linux/types.h>
-#include <linux/autoconf.h>
 
 void * memcpy(void * to, const void * from, size_t n)
 {
index 8527856aec45c2c36dff1a15b83ef2d12ca97571..0b658f1db4cedde3021e4eea3916091b36e4ab87 100644 (file)
@@ -27,7 +27,6 @@
  *     others have a second one : GPIO2
  */
 
-#include <linux/autoconf.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/types.h>
index c032409cba9b50b7df4bfad7988dd26ad0d00213..39f3dfe134fb9cb619c3c49d48de00be105a9490 100644 (file)
@@ -232,7 +232,7 @@ static void __init finalize_initrd(void)
                goto disable;
        }
 
-       reserve_bootmem(__pa(initrd_start), size);
+       reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT);
        initrd_below_start_ok = 1;
 
        printk(KERN_INFO "Initial ramdisk at: 0x%lx (%lu bytes)\n",
@@ -413,7 +413,7 @@ static void __init bootmem_init(void)
        /*
         * Reserve the bootmap memory.
         */
-       reserve_bootmem(PFN_PHYS(mapstart), bootmap_size);
+       reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT);
 
        /*
         * Reserve initrd memory if needed.
index 1e5dfc28294a48efac28259fc610c37db4b257e0..9d41dab90a809732e1c2eab6ed234e989d5637cd 100644 (file)
@@ -52,7 +52,6 @@ int __cpu_logical_map[NR_CPUS];               /* Map logical to physical */
 EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(cpu_online_map);
 
-extern void __init calibrate_delay(void);
 extern void cpu_idle(void);
 
 /* Number of TCs (or siblings in Intel speak) per CPU core */
index 4c477c7ff74a1388c21a85392ed19ac7033cbeec..22fd41e946b28c3d9e2a8a853c4951bcada5b629 100644 (file)
@@ -356,7 +356,7 @@ asmlinkage int irix_syssgi(struct pt_regs *regs)
                        retval = NGROUPS_MAX;
                        goto out;
                case 5:
-                       retval = NR_OPEN;
+                       retval = sysctl_nr_open;
                        goto out;
                case 6:
                        retval = 1;
index e5e023f50a07d3f01b74361af21038f31ab05730..bf438d02366e4823aa5849d9592b9163bfb088ae 100644 (file)
@@ -465,7 +465,8 @@ static void __init node_mem_init(cnodeid_t node)
        free_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
                        (slot_lastpfn - slot_firstpfn) << PAGE_SHIFT);
        reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
-               ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size);
+               ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size,
+               BOOTMEM_DEFAULT);
 }
 
 /*
index 9166bd1172675c2cbadd1c80de98042005e6c30b..bc989e522a045c17ca4514478b7cb5ef9d77fc4d 100644 (file)
@@ -2,15 +2,6 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-config DEBUG_RWLOCK
-        bool "Read-write spinlock debugging"
-        depends on DEBUG_KERNEL && SMP
-        help
-          If you say Y here then read-write lock processing will count how many
-          times it has tried to get the lock and issue an error message after
-          too many attempts.  If you suspect a rwlock problem or a kernel
-          hacker asks for this option then say Y.  Otherwise say N.
-
 config DEBUG_RODATA
        bool "Write protect kernel read-only data structures"
        depends on DEBUG_KERNEL
index ea071218a3ed2cf68b4e1e98e7fa91ac2355101b..ddacc72e38fb8e92b1bac2a1d5cc30743924f75d 100644 (file)
@@ -1050,7 +1050,6 @@ CONFIG_SCHED_DEBUG=y
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_DEBUG_RWLOCK is not set
 # CONFIG_DEBUG_RODATA is not set
 
 #
index aa875fa43488b8a835e2b6d079871832bc0c308f..eb80f5e33d7dad11b2cb11b9e8a2b9136c0863dc 100644 (file)
@@ -315,11 +315,13 @@ static void __init setup_bootmem(void)
 #define PDC_CONSOLE_IO_IODC_SIZE 32768
 
        reserve_bootmem_node(NODE_DATA(0), 0UL,
-                       (unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
+                       (unsigned long)(PAGE0->mem_free +
+                               PDC_CONSOLE_IO_IODC_SIZE), BOOTMEM_DEFAULT);
        reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text),
-                       (unsigned long)(_end - _text));
+                       (unsigned long)(_end - _text), BOOTMEM_DEFAULT);
        reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
-                       ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
+                       ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT),
+                       BOOTMEM_DEFAULT);
 
 #ifndef CONFIG_DISCONTIGMEM
 
@@ -328,7 +330,8 @@ static void __init setup_bootmem(void)
        for (i = 0; i < npmem_holes; i++) {
                reserve_bootmem_node(NODE_DATA(0),
                                (pmem_holes[i].start_pfn << PAGE_SHIFT),
-                               (pmem_holes[i].pages << PAGE_SHIFT));
+                               (pmem_holes[i].pages << PAGE_SHIFT),
+                               BOOTMEM_DEFAULT);
        }
 #endif
 
@@ -346,7 +349,8 @@ static void __init setup_bootmem(void)
                        initrd_below_start_ok = 1;
                        printk(KERN_INFO "initrd: reserving %08lx-%08lx (mem_max %08lx)\n", __pa(initrd_start), __pa(initrd_start) + initrd_reserve, mem_max);
 
-                       reserve_bootmem_node(NODE_DATA(0),__pa(initrd_start), initrd_reserve);
+                       reserve_bootmem_node(NODE_DATA(0), __pa(initrd_start),
+                                       initrd_reserve, BOOTMEM_DEFAULT);
                }
        }
 #endif
index 5cd3db5cae415198653a8d1a4e4bce846a7a40ef..3b26fbd6bec9ee4978ff6430ce1ef27a55723089 100644 (file)
@@ -66,6 +66,7 @@
 #include <asm/smp.h>
 #include <asm/vdso_datapage.h>
 #include <asm/firmware.h>
+#include <asm/cputime.h>
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iseries/it_lp_queue.h>
 #include <asm/iseries/hv_call_xm.h>
@@ -189,6 +190,8 @@ u64 __cputime_sec_factor;
 EXPORT_SYMBOL(__cputime_sec_factor);
 u64 __cputime_clockt_factor;
 EXPORT_SYMBOL(__cputime_clockt_factor);
+DEFINE_PER_CPU(unsigned long, cputime_last_delta);
+DEFINE_PER_CPU(unsigned long, cputime_scaled_last_delta);
 
 static void calc_cputime_factors(void)
 {
@@ -257,8 +260,8 @@ void account_system_vtime(struct task_struct *tsk)
        }
        account_system_time(tsk, 0, delta);
        account_system_time_scaled(tsk, deltascaled);
-       get_paca()->purrdelta = delta;
-       get_paca()->spurrdelta = deltascaled;
+       per_cpu(cputime_last_delta, smp_processor_id()) = delta;
+       per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled;
        local_irq_restore(flags);
 }
 
@@ -276,10 +279,7 @@ void account_process_tick(struct task_struct *tsk, int user_tick)
        get_paca()->user_time = 0;
        account_user_time(tsk, utime);
 
-       /* Estimate the scaled utime by scaling the real utime based
-        * on the last spurr to purr ratio */
-       utimescaled = utime * get_paca()->spurrdelta / get_paca()->purrdelta;
-       get_paca()->spurrdelta = get_paca()->purrdelta = 0;
+       utimescaled = cputime_to_scaled(utime);
        account_user_time_scaled(tsk, utimescaled);
 }
 
index c7d7bd43a251a2feeedfa89a6f8a33e0687dacb4..93a5c53e3423fe7c5663b411cfe53cd82da73ad9 100644 (file)
@@ -220,12 +220,13 @@ void __init do_init_bootmem(void)
                                     lmb_size_bytes(&lmb.reserved, i) - 1;
                if (addr < total_lowmem)
                        reserve_bootmem(lmb.reserved.region[i].base,
-                                       lmb_size_bytes(&lmb.reserved, i));
+                                       lmb_size_bytes(&lmb.reserved, i),
+                                       BOOTMEM_DEFAULT);
                else if (lmb.reserved.region[i].base < total_lowmem) {
                        unsigned long adjusted_size = total_lowmem -
                                      lmb.reserved.region[i].base;
                        reserve_bootmem(lmb.reserved.region[i].base,
-                                       adjusted_size);
+                                       adjusted_size, BOOTMEM_DEFAULT);
                }
        }
 #else
@@ -234,7 +235,8 @@ void __init do_init_bootmem(void)
        /* reserve the sections we're already using */
        for (i = 0; i < lmb.reserved.cnt; i++)
                reserve_bootmem(lmb.reserved.region[i].base,
-                               lmb_size_bytes(&lmb.reserved, i));
+                               lmb_size_bytes(&lmb.reserved, i),
+                               BOOTMEM_DEFAULT);
 
 #endif
        /* XXX need to clip this if using highmem? */
index e9139d267ea47c0477a8388b2defdb2e8553b38a..a300d254aac6518dc473ecf405bebf6943b6bfeb 100644 (file)
@@ -731,7 +731,7 @@ void __init do_init_bootmem(void)
                                dbg("reserve_bootmem %lx %lx\n", physbase,
                                    size);
                                reserve_bootmem_node(NODE_DATA(nid), physbase,
-                                                    size);
+                                                    size, BOOTMEM_DEFAULT);
                        }
                }
 
index c04abcc28a7a88060a9cb6be50922c9ef41bd4a9..792d3ce8112e0778425cfc1f3531db3fb8e69776 100644 (file)
@@ -113,8 +113,6 @@ static inline void debug_calc_bogomips(void)
         * result. We backup/restore the value to avoid affecting the
         * core cpufreq framework's own calculation.
         */
-       extern void calibrate_delay(void);
-
        unsigned long save_lpj = loops_per_jiffy;
        calibrate_delay();
        loops_per_jiffy = save_lpj;
index 25ef55bacd99e50545caf74b8a493b15622425a6..ec1defea9c1e4885fe974722c8dc8cb00d45eac3 100644 (file)
@@ -418,7 +418,7 @@ scc_enet_rx(struct net_device *dev)
        struct  sk_buff *skb;
        ushort  pkt_len;
 
-       cep = (struct scc_enet_private *)dev->priv;
+       cep = dev->priv;
 
        /* First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
index a3a27dafff1fc73fc3d1ebc777213fc3a9819598..bcc3aa9d04f397fa62f7ef83fef80262c2eba942 100644 (file)
@@ -682,7 +682,7 @@ fcc_enet_rx(struct net_device *dev)
        struct  sk_buff *skb;
        ushort  pkt_len;
 
-       cep = (struct fcc_enet_private *)dev->priv;
+       cep = dev->priv;
 
        /* First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
index 52b64fcbdfc50d493a76bef799400e2365cdd15e..8a24bc47eb6cc76f52496d0efd9417f827c0c586 100644 (file)
@@ -143,11 +143,6 @@ SECTIONS
 
   . = ALIGN(4096);
   __init_end = .;
-
-  . = ALIGN(4096);
-  _sextratext = .;
-  _eextratext = .;
-
   __bss_start = .;
   .bss       :
   {
index 3c56654bfc6f28580a42a7e4cc4a043dcd8e300d..38449855d5ffbede401cf147a5d8af8a76abc086 100644 (file)
@@ -91,20 +91,11 @@ extern void prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi
 #define cached_21      (((char *)(ppc_cached_irq_mask))[3])
 #define cached_A1      (((char *)(ppc_cached_irq_mask))[2])
 
-#ifdef CONFIG_SOUND_CS4232
-long ppc_cs4232_dma, ppc_cs4232_dma2;
-#endif
-
 extern PTE *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
 extern int probingmem;
 extern unsigned long loops_per_jiffy;
 
-#ifdef CONFIG_SOUND_CS4232
-EXPORT_SYMBOL(ppc_cs4232_dma);
-EXPORT_SYMBOL(ppc_cs4232_dma2);
-#endif
-
 /* useful ISA ports */
 #define PREP_SYSCTL    0x81c
 /* present in the IBM reference design; possibly identical in Mot boxes: */
@@ -569,74 +560,6 @@ prep_show_percpuinfo(struct seq_file *m, int i)
        return 0;
 }
 
-#ifdef CONFIG_SOUND_CS4232
-static long __init masktoint(unsigned int i)
-{
-       int t = -1;
-       while (i >> ++t)
-               ;
-       return (t-1);
-}
-
-/*
- * ppc_cs4232_dma and ppc_cs4232_dma2 are used in include/asm/dma.h
- * to distinguish sound dma-channels from others. This is because
- * blocksize on 16 bit dma-channels 5,6,7 is 128k, but
- * the cs4232.c uses 64k like on 8 bit dma-channels 0,1,2,3
- */
-
-static void __init prep_init_sound(void)
-{
-       PPC_DEVICE *audiodevice = NULL;
-
-       /*
-        * Get the needed resource information from residual data.
-        *
-        */
-       if (have_residual_data)
-               audiodevice = residual_find_device(~0, NULL,
-                               MultimediaController, AudioController, -1, 0);
-
-       if (audiodevice != NULL) {
-               PnP_TAG_PACKET *pkt;
-
-               pkt = PnP_find_packet((unsigned char *)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
-                               S5_Packet, 0);
-               if (pkt != NULL)
-                       ppc_cs4232_dma = masktoint(pkt->S5_Pack.DMAMask);
-               pkt = PnP_find_packet((unsigned char*)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
-                               S5_Packet, 1);
-               if (pkt != NULL)
-                       ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask);
-       }
-
-       /*
-        * These are the PReP specs' defaults for the cs4231.  We use these
-        * as fallback incase we don't have residual data.
-        * At least the IBM Thinkpad 850 with IDE DMA Channels at 6 and 7
-        * will use the other values.
-        */
-       if (audiodevice == NULL) {
-               switch (_prep_type) {
-               case _PREP_IBM:
-                       ppc_cs4232_dma = 1;
-                       ppc_cs4232_dma2 = -1;
-                       break;
-               default:
-                       ppc_cs4232_dma = 6;
-                       ppc_cs4232_dma2 = 7;
-               }
-       }
-
-       /*
-        * Find a way to push this information to the cs4232 driver
-        * Give it out with printk, when not in cmd_line?
-        * Append it to cmd_line and boot_command_line?
-        * Format is cs4232=io,irq,dma,dma2
-        */
-}
-#endif /* CONFIG_SOUND_CS4232 */
-
 /*
  * Fill out screen_info according to the residual data. This allows us to use
  * at least vesafb.
@@ -898,10 +821,6 @@ prep_setup_arch(void)
                }
        }
 
-#ifdef CONFIG_SOUND_CS4232
-       prep_init_sound();
-#endif /* CONFIG_SOUND_CS4232 */
-
        prep_init_vesa();
 
        switch (_prep_type) {
index 29ae165d174931b0d7b1775e3690c1be23d5c8f9..f9f8779022a0dc5c218b56628b00bd1c49d33c34 100644 (file)
@@ -649,21 +649,24 @@ setup_memory(void)
        /*
         * Reserve memory used for lowcore/command line/kernel image.
         */
-       reserve_bootmem(0, (unsigned long)_ehead);
+       reserve_bootmem(0, (unsigned long)_ehead, BOOTMEM_DEFAULT);
        reserve_bootmem((unsigned long)_stext,
-                       PFN_PHYS(start_pfn) - (unsigned long)_stext);
+                       PFN_PHYS(start_pfn) - (unsigned long)_stext,
+                       BOOTMEM_DEFAULT);
        /*
         * Reserve the bootmem bitmap itself as well. We do this in two
         * steps (first step was init_bootmem()) because this catches
         * the (very unlikely) case of us accidentally initializing the
         * bootmem allocator with an invalid RAM area.
         */
-       reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
+       reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size,
+                       BOOTMEM_DEFAULT);
 
 #ifdef CONFIG_BLK_DEV_INITRD
        if (INITRD_START && INITRD_SIZE) {
                if (INITRD_START + INITRD_SIZE <= memory_end) {
-                       reserve_bootmem(INITRD_START, INITRD_SIZE);
+                       reserve_bootmem(INITRD_START, INITRD_SIZE,
+                                       BOOTMEM_DEFAULT);
                        initrd_start = INITRD_START;
                        initrd_end = initrd_start + INITRD_SIZE;
                } else {
index eda71763ecc5281c1173012d9767a18f7300c580..2b708ec7255868981874b87354fae33661529376 100644 (file)
@@ -14,7 +14,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/pm.h>
 #include <linux/mm.h>
 #include <asm/machvec.h>
index 9c830fdc411b346b056ed2b5885bcae750adcc26..c74440d38ee974aa40482ed5a2af56334f25e9a1 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <asm/machvec.h>
 #include <asm/addrspace.h>
 #include <asm/lboxre2.h>
index a43b47726f545539467a8325c845648cea01b300..f7a8d5c9d510577f085f0ac3f96bcf5ffeb10cc7 100644 (file)
@@ -15,7 +15,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/types.h>
 #include <net/ax88796.h>
 #include <asm/machvec.h>
index 3452b072addece1706a68720e48c32bd52e83c54..a0ef81b7de3743e42c6933dc5f2e82481f0f89c6 100644 (file)
@@ -10,7 +10,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/serial_8250.h>
 #include <linux/sm501.h>
 #include <linux/sm501-regs.h>
index 5df32f2018703a557ed7fc63b39d565f6d8457aa..acc5932587f11ad994793d1f5d6941b2aa8bcdc3 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <asm/machvec.h>
 #include <asm/sdk7780.h>
 #include <asm/heartbeat.h>
index eb97dca5b736c4fce596c74c55476ace350b3424..b1a3d9d0172f50678c5add2c1388bb5094afbcf2 100644 (file)
@@ -12,7 +12,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <asm/machvec.h>
 #include <asm/se7722.h>
 #include <asm/io.h>
index 855cdf9d85b1867c47dde1974a818f745f6ddb85..18a5baf2cbadbe848003310dbd195d44fdcbbe0b 100644 (file)
@@ -140,18 +140,26 @@ static void __init reserve_crashkernel(void)
        ret = parse_crashkernel(boot_command_line, free_mem,
                        &crash_size, &crash_base);
        if (ret == 0 && crash_size) {
-               if (crash_base > 0) {
-                       printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
-                                       "for crashkernel (System RAM: %ldMB)\n",
-                                       (unsigned long)(crash_size >> 20),
-                                       (unsigned long)(crash_base >> 20),
-                                       (unsigned long)(free_mem >> 20));
-                       crashk_res.start = crash_base;
-                       crashk_res.end   = crash_base + crash_size - 1;
-                       reserve_bootmem(crash_base, crash_size);
-               } else
+               if (crash_base <= 0) {
                        printk(KERN_INFO "crashkernel reservation failed - "
                                        "you have to specify a base address\n");
+                       return;
+               }
+
+               if (reserve_bootmem(crash_base, crash_size,
+                                       BOOTMEM_EXCLUSIVE) < 0) {
+                       printk(KERN_INFO "crashkernel reservation failed - "
+                                       "memory is in use\n");
+                       return;
+               }
+
+               printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
+                               "for crashkernel (System RAM: %ldMB)\n",
+                               (unsigned long)(crash_size >> 20),
+                               (unsigned long)(crash_base >> 20),
+                               (unsigned long)(free_mem >> 20));
+               crashk_res.start = crash_base;
+               crashk_res.end   = crash_base + crash_size - 1;
        }
 }
 #else
@@ -184,13 +192,14 @@ void __init setup_bootmem_allocator(unsigned long free_pfn)
         * an invalid RAM area.
         */
        reserve_bootmem(__MEMORY_START+PAGE_SIZE,
-               (PFN_PHYS(free_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
+               (PFN_PHYS(free_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START,
+               BOOTMEM_DEFAULT);
 
        /*
         * reserve physical page 0 - it's a special BIOS page on many boxes,
         * enabling clean reboots, SMP operation, laptop functions.
         */
-       reserve_bootmem(__MEMORY_START, PAGE_SIZE);
+       reserve_bootmem(__MEMORY_START, PAGE_SIZE, BOOTMEM_DEFAULT);
 
        sparse_memory_present_with_active_regions(0);
 
@@ -200,7 +209,7 @@ void __init setup_bootmem_allocator(unsigned long free_pfn)
        if (LOADER_TYPE && INITRD_START) {
                if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
                        reserve_bootmem(INITRD_START + __MEMORY_START,
-                                       INITRD_SIZE);
+                                       INITRD_SIZE, BOOTMEM_DEFAULT);
                        initrd_start = INITRD_START + PAGE_OFFSET +
                                        __MEMORY_START;
                        initrd_end = initrd_start + INITRD_SIZE;
index 8aff065dd30714c842a5cbf828d7eb71e5d28355..2de7302724fc188cd6a8bf9680470bc55fad2dc7 100644 (file)
@@ -80,9 +80,9 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
 
        /* Reserve the pgdat and bootmap space with the bootmem allocator */
        reserve_bootmem_node(NODE_DATA(nid), start_pfn << PAGE_SHIFT,
-                            sizeof(struct pglist_data));
+                            sizeof(struct pglist_data), BOOTMEM_DEFAULT);
        reserve_bootmem_node(NODE_DATA(nid), free_pfn << PAGE_SHIFT,
-                            bootmap_pages << PAGE_SHIFT);
+                            bootmap_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);
 
        /* It's up */
        node_set_online(nid);
index 89a6de95070c761d0fe3237bc89a49f2063fc1fb..0def48158c7d165ca34688a51053205372e79cf4 100644 (file)
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/profile.h>
+#include <linux/delay.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 #include <asm/irq_regs.h>
 
-#include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
@@ -41,8 +41,6 @@
 
 extern ctxd_t *srmmu_ctx_table_phys;
 
-extern void calibrate_delay(void);
-
 static volatile int smp_processors_ready = 0;
 static int smp_highest_cpu;
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
index 730eb5796f8edb98b83332e4a9099996ca1e3083..0b94072671623287c6c819fb4f405b18a0bb7038 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/profile.h>
+#include <linux/delay.h>
+
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/irq_regs.h>
@@ -23,7 +25,6 @@
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 
-#include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
@@ -39,8 +40,6 @@
 
 extern ctxd_t *srmmu_ctx_table_phys;
 
-extern void calibrate_delay(void);
-
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
 extern unsigned char boot_cpu_id;
 
index ee010f4532a0dd3979b764b99f0b775f795f61d3..9064485dc40be66266882a5fd3a13531344610d1 100644 (file)
@@ -79,7 +79,8 @@ sys_call_table:
 /*295*/        .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 /*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .long sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate
+/*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
+/*315*/        .long sys_timerfd_settime, sys_timerfd_gettime
 
 #ifdef CONFIG_SUNOS_EMUL
        /* Now the SunOS syscall table. */
@@ -197,6 +198,7 @@ sunos_sys_table:
        .long sunos_nosys, sunos_nosys, sunos_nosys
        .long sunos_nosys
 /*310*/        .long sunos_nosys, sunos_nosys, sunos_nosys
-       .long sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys
 
 #endif
index a1bef07755a920076d186880269af56f5f9348db..b89837accc88574e9554706ab1084e8fd642250a 100644 (file)
@@ -259,7 +259,7 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
        if (initrd_start) {
                /* Reserve the initrd image area. */
                size = initrd_end - initrd_start;
-               reserve_bootmem(initrd_start, size);
+               reserve_bootmem(initrd_start, size, BOOTMEM_DEFAULT);
                *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
                initrd_start = (initrd_start - phys_base) + PAGE_OFFSET;
@@ -268,7 +268,7 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
 #endif
        /* Reserve the kernel text/data/bss. */
        size = (start_pfn << PAGE_SHIFT) - phys_base;
-       reserve_bootmem(phys_base, size);
+       reserve_bootmem(phys_base, size, BOOTMEM_DEFAULT);
        *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
        /* Reserve the bootmem map.   We do not account for it
@@ -276,7 +276,7 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
         * in free_all_bootmem.
         */
        size = bootmap_size;
-       reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
+       reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size, BOOTMEM_DEFAULT);
        *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
        return max_pfn;
index f62d9f6c5e2a8d45519b1dba2a454e1faa718d1a..833d74b2b1923faa08e95c3604f2bbb5a7dddb86 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.24-rc4
-# Tue Dec  4 00:37:59 2007
+# Linux kernel version: 2.6.24
+# Tue Feb  5 17:28:19 2008
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -17,6 +17,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_AUDIT_ARCH=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_OF=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
@@ -30,13 +31,15 @@ CONFIG_HZ_100=y
 # CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=100
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_HOTPLUG_CPU=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
 # General setup
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
@@ -76,6 +79,7 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -83,6 +87,14 @@ CONFIG_SLUB_DEBUG=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=m
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
@@ -92,6 +104,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
 CONFIG_BLOCK=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_BLK_DEV_BSG=y
@@ -109,6 +122,8 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_RCU is not set
 CONFIG_SYSVIPC_COMPAT=y
 CONFIG_GENERIC_HARDIRQS=y
 
@@ -119,7 +134,8 @@ CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-# CONFIG_SMP is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=64
 # CONFIG_CPU_FREQ is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -169,9 +185,12 @@ CONFIG_BINFMT_ELF32=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 CONFIG_SOLARIS_EMUL=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_MC=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
+# CONFIG_RCU_TRACE is not set
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -189,6 +208,7 @@ CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 # CONFIG_XFRM_SUB_POLICY is not set
 CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
 CONFIG_NET_KEY=m
 CONFIG_NET_KEY_MIGRATE=y
 CONFIG_INET=y
@@ -249,9 +269,9 @@ CONFIG_IP_DCCP_ACKVEC=y
 CONFIG_IP_DCCP_CCID2=m
 # CONFIG_IP_DCCP_CCID2_DEBUG is not set
 CONFIG_IP_DCCP_CCID3=m
-CONFIG_IP_DCCP_TFRC_LIB=m
 # CONFIG_IP_DCCP_CCID3_DEBUG is not set
 CONFIG_IP_DCCP_CCID3_RTO=100
+CONFIG_IP_DCCP_TFRC_LIB=m
 
 #
 # DCCP Kernel Hacking
@@ -279,6 +299,7 @@ CONFIG_VLAN_8021Q=m
 CONFIG_NET_PKTGEN=m
 CONFIG_NET_TCPPROBE=m
 # CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
@@ -343,6 +364,7 @@ CONFIG_BLK_DEV_IDE=y
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
@@ -359,7 +381,6 @@ CONFIG_IDE_GENERIC=y
 # PCI IDE chipsets support
 #
 CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
@@ -389,7 +410,6 @@ CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_BLK_DEV_TC86C001 is not set
-# CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_IDE_ARCH_OBSOLETE_INIT=y
 # CONFIG_BLK_DEV_HD is not set
@@ -501,7 +521,6 @@ CONFIG_NETDEVICES=y
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_VETH is not set
-# CONFIG_IP1000 is not set
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
@@ -533,6 +552,7 @@ CONFIG_NET_PCI=y
 # CONFIG_NE2K_PCI is not set
 # CONFIG_8139CP is not set
 # CONFIG_8139TOO is not set
+# CONFIG_R6040 is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -545,6 +565,9 @@ CONFIG_E1000=m
 CONFIG_E1000_NAPI=y
 # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
 # CONFIG_E1000E is not set
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
@@ -570,6 +593,7 @@ CONFIG_NETDEV_10000=y
 CONFIG_NIU=m
 # CONFIG_MLX4_CORE is not set
 # CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
 # CONFIG_TR is not set
 
 #
@@ -602,7 +626,6 @@ CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 CONFIG_SLHC=m
 # CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
@@ -679,6 +702,7 @@ CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
 # CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
 
 #
 # Serial drivers
@@ -747,13 +771,13 @@ CONFIG_I2C_ALGOBIT=y
 #
 # Miscellaneous I2C Chip support
 #
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
 # CONFIG_DS1682 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
@@ -990,6 +1014,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_BT87X is not set
 # CONFIG_SND_CA0106 is not set
 # CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS46XX is not set
 # CONFIG_SND_DARLA20 is not set
@@ -1014,6 +1039,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_HDA_INTEL is not set
 # CONFIG_SND_HDSP is not set
 # CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
@@ -1031,6 +1057,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
 # CONFIG_SND_VX222 is not set
 # CONFIG_SND_YMFPCI is not set
 # CONFIG_SND_AC97_POWER_SAVE is not set
@@ -1057,6 +1084,10 @@ CONFIG_SND_SUN_CS4231=m
 # SoC Audio support for SuperH
 #
 
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
 #
 # Open Sound System
 #
@@ -1080,6 +1111,7 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
 
 #
 # Miscellaneous USB options
@@ -1093,7 +1125,6 @@ CONFIG_USB_DEVICEFS=y
 # USB Host Controller Drivers
 #
 CONFIG_USB_EHCI_HCD=m
-# CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
 # CONFIG_USB_ISP116X_HCD is not set
@@ -1143,10 +1174,6 @@ CONFIG_USB_STORAGE=m
 #
 # USB port drivers
 #
-
-#
-# USB Serial Converter support
-#
 # CONFIG_USB_SERIAL is not set
 
 #
@@ -1172,14 +1199,6 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
 # CONFIG_USB_GADGET is not set
 # CONFIG_MMC is not set
 # CONFIG_NEW_LEDS is not set
@@ -1332,11 +1351,6 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 # CONFIG_DLM is not set
-CONFIG_INSTRUMENTATION=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_KPROBES=y
-# CONFIG_MARKERS is not set
 
 #
 # Kernel hacking
@@ -1374,6 +1388,8 @@ CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FORCED_INLINING=y
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_LKDTM is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_SAMPLES is not set
@@ -1396,8 +1412,9 @@ CONFIG_ASYNC_MEMCPY=m
 CONFIG_ASYNC_XOR=m
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD=y
 CONFIG_CRYPTO_BLKCIPHER=y
+# CONFIG_CRYPTO_SEQIV is not set
 CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_HMAC=y
@@ -1416,6 +1433,9 @@ CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_XTS=m
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_CCM is not set
 # CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_FCRYPT=m
@@ -1431,13 +1451,16 @@ CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_SEED=m
+# CONFIG_CRYPTO_SALSA20 is not set
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_AUTHENC=m
+# CONFIG_CRYPTO_LZO is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
 
 #
 # Library routines
index ef50d217432f151f1ab3ed6e701d3ed2281c9afd..4b78b24ef413744c579d935355f6a3c0c0d06cda 100644 (file)
@@ -11,7 +11,7 @@ obj-y         := process.o setup.o cpu.o idprom.o \
                   traps.o auxio.o una_asm.o sysfs.o iommu.o \
                   irq.o ptrace.o time.o sys_sparc.o signal.o \
                   unaligned.o central.o pci.o starfire.o semaphore.o \
-                  power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
+                  power.o sbus.o sparc64_ksyms.o chmc.o \
                   visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
 
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
index 4b9115a4d92ecf909d17a0a5e5c1964b450dfe35..5623a4d59dff0a642ca0e468527214d9b456384a 100644 (file)
@@ -472,94 +472,15 @@ static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr,
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-#define SG_ENT_PHYS_ADDRESS(SG)        (__pa(sg_virt((SG))))
-
-static void fill_sg(iopte_t *iopte, struct scatterlist *sg,
-                   int nused, int nelems,
-                   unsigned long iopte_protection)
-{
-       struct scatterlist *dma_sg = sg;
-       int i;
-
-       for (i = 0; i < nused; i++) {
-               unsigned long pteval = ~0UL;
-               u32 dma_npages;
-
-               dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
-                             dma_sg->dma_length +
-                             ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
-               do {
-                       unsigned long offset;
-                       signed int len;
-
-                       /* If we are here, we know we have at least one
-                        * more page to map.  So walk forward until we
-                        * hit a page crossing, and begin creating new
-                        * mappings from that spot.
-                        */
-                       for (;;) {
-                               unsigned long tmp;
-
-                               tmp = SG_ENT_PHYS_ADDRESS(sg);
-                               len = sg->length;
-                               if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
-                                       pteval = tmp & IO_PAGE_MASK;
-                                       offset = tmp & (IO_PAGE_SIZE - 1UL);
-                                       break;
-                               }
-                               if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
-                                       pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
-                                       offset = 0UL;
-                                       len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
-                                       break;
-                               }
-                               sg = sg_next(sg);
-                               nelems--;
-                       }
-
-                       pteval = iopte_protection | (pteval & IOPTE_PAGE);
-                       while (len > 0) {
-                               *iopte++ = __iopte(pteval);
-                               pteval += IO_PAGE_SIZE;
-                               len -= (IO_PAGE_SIZE - offset);
-                               offset = 0;
-                               dma_npages--;
-                       }
-
-                       pteval = (pteval & IOPTE_PAGE) + len;
-                       sg = sg_next(sg);
-                       nelems--;
-
-                       /* Skip over any tail mappings we've fully mapped,
-                        * adjusting pteval along the way.  Stop when we
-                        * detect a page crossing event.
-                        */
-                       while (nelems &&
-                              (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
-                              (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
-                              ((pteval ^
-                                (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
-                               pteval += sg->length;
-                               sg = sg_next(sg);
-                               nelems--;
-                       }
-                       if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
-                               pteval = ~0UL;
-               } while (dma_npages != 0);
-               dma_sg = sg_next(dma_sg);
-       }
-}
-
 static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
                         int nelems, enum dma_data_direction direction)
 {
-       struct iommu *iommu;
+       unsigned long flags, ctx, i, npages, iopte_protection;
+       struct scatterlist *sg;
        struct strbuf *strbuf;
-       unsigned long flags, ctx, npages, iopte_protection;
+       struct iommu *iommu;
        iopte_t *base;
        u32 dma_base;
-       struct scatterlist *sgtmp;
-       int used;
 
        /* Fast path single entry scatterlists. */
        if (nelems == 1) {
@@ -578,11 +499,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
        if (unlikely(direction == DMA_NONE))
                goto bad_no_ctx;
 
-       /* Step 1: Prepare scatter list. */
-
-       npages = prepare_sg(dev, sglist, nelems);
-
-       /* Step 2: Allocate a cluster and context, if necessary. */
+       npages = calc_npages(sglist, nelems);
 
        spin_lock_irqsave(&iommu->lock, flags);
 
@@ -599,18 +516,6 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
        dma_base = iommu->page_table_map_base +
                ((base - iommu->page_table) << IO_PAGE_SHIFT);
 
-       /* Step 3: Normalize DMA addresses. */
-       used = nelems;
-
-       sgtmp = sglist;
-       while (used && sgtmp->dma_length) {
-               sgtmp->dma_address += dma_base;
-               sgtmp = sg_next(sgtmp);
-               used--;
-       }
-       used = nelems - used;
-
-       /* Step 4: Create the mappings. */
        if (strbuf->strbuf_enabled)
                iopte_protection = IOPTE_STREAMING(ctx);
        else
@@ -618,13 +523,27 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
        if (direction != DMA_TO_DEVICE)
                iopte_protection |= IOPTE_WRITE;
 
-       fill_sg(base, sglist, used, nelems, iopte_protection);
+       for_each_sg(sglist, sg, nelems, i) {
+               unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
+               unsigned long slen = sg->length;
+               unsigned long this_npages;
 
-#ifdef VERIFY_SG
-       verify_sglist(sglist, nelems, base, npages);
-#endif
+               this_npages = iommu_num_pages(paddr, slen);
 
-       return used;
+               sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK);
+               sg->dma_length = slen;
+
+               paddr &= IO_PAGE_MASK;
+               while (this_npages--) {
+                       iopte_val(*base) = iopte_protection | paddr;
+
+                       base++;
+                       paddr += IO_PAGE_SIZE;
+                       dma_base += IO_PAGE_SIZE;
+               }
+       }
+
+       return nelems;
 
 bad:
        iommu_free_ctx(iommu, ctx);
@@ -637,11 +556,10 @@ bad_no_ctx:
 static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
                            int nelems, enum dma_data_direction direction)
 {
-       struct iommu *iommu;
+       unsigned long flags, ctx, i, npages;
        struct strbuf *strbuf;
+       struct iommu *iommu;
        iopte_t *base;
-       unsigned long flags, ctx, i, npages;
-       struct scatterlist *sg, *sgprv;
        u32 bus_addr;
 
        if (unlikely(direction == DMA_NONE)) {
@@ -654,15 +572,7 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
 
        bus_addr = sglist->dma_address & IO_PAGE_MASK;
 
-       sgprv = NULL;
-       for_each_sg(sglist, sg, nelems, i) {
-               if (sg->dma_length == 0)
-                       break;
-               sgprv = sg;
-       }
-
-       npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) -
-                 bus_addr) >> IO_PAGE_SHIFT;
+       npages = calc_npages(sglist, nelems);
 
        base = iommu->page_table +
                ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c
deleted file mode 100644 (file)
index 72a4acf..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/* $Id: iommu_common.c,v 1.9 2001/12/17 07:05:09 davem Exp $
- * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
- *
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
- */
-
-#include <linux/dma-mapping.h>
-#include "iommu_common.h"
-
-/* You are _strongly_ advised to enable the following debugging code
- * any time you make changes to the sg code below, run it for a while
- * with filesystems mounted read-only before buying the farm... -DaveM
- */
-
-#ifdef VERIFY_SG
-static int verify_lengths(struct scatterlist *sglist, int nents, int npages)
-{
-       int sg_len, dma_len;
-       int i, pgcount;
-       struct scatterlist *sg;
-
-       sg_len = 0;
-       for_each_sg(sglist, sg, nents, i)
-               sg_len += sg->length;
-
-       dma_len = 0;
-       for_each_sg(sglist, sg, nents, i) {
-               if (!sg->dma_length)
-                       break;
-               dma_len += sg->dma_length;
-       }
-
-       if (sg_len != dma_len) {
-               printk("verify_lengths: Error, different, sg[%d] dma[%d]\n",
-                      sg_len, dma_len);
-               return -1;
-       }
-
-       pgcount = 0;
-       for_each_sg(sglist, sg, nents, i) {
-               unsigned long start, end;
-
-               if (!sg->dma_length)
-                       break;
-
-               start = sg->dma_address;
-               start = start & IO_PAGE_MASK;
-
-               end = sg->dma_address + sg->dma_length;
-               end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK;
-
-               pgcount += ((end - start) >> IO_PAGE_SHIFT);
-       }
-
-       if (pgcount != npages) {
-               printk("verify_lengths: Error, page count wrong, "
-                      "npages[%d] pgcount[%d]\n",
-                      npages, pgcount);
-               return -1;
-       }
-
-       /* This test passes... */
-       return 0;
-}
-
-static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte)
-{
-       struct scatterlist *sg = *__sg;
-       iopte_t *iopte = *__iopte;
-       u32 dlen = dma_sg->dma_length;
-       u32 daddr;
-       unsigned int sglen;
-       unsigned long sgaddr;
-
-       daddr = dma_sg->dma_address;
-       sglen = sg->length;
-       sgaddr = (unsigned long) sg_virt(sg);
-       while (dlen > 0) {
-               unsigned long paddr;
-
-               /* SG and DMA_SG must begin at the same sub-page boundary. */
-               if ((sgaddr & ~IO_PAGE_MASK) != (daddr & ~IO_PAGE_MASK)) {
-                       printk("verify_one_map: Wrong start offset "
-                              "sg[%08lx] dma[%08x]\n",
-                              sgaddr, daddr);
-                       nents = -1;
-                       goto out;
-               }
-
-               /* Verify the IOPTE points to the right page. */
-               paddr = iopte_val(*iopte) & IOPTE_PAGE;
-               if ((paddr + PAGE_OFFSET) != (sgaddr & IO_PAGE_MASK)) {
-                       printk("verify_one_map: IOPTE[%08lx] maps the "
-                              "wrong page, should be [%08lx]\n",
-                              iopte_val(*iopte), (sgaddr & IO_PAGE_MASK) - PAGE_OFFSET);
-                       nents = -1;
-                       goto out;
-               }
-
-               /* If this SG crosses a page, adjust to that next page
-                * boundary and loop.
-                */
-               if ((sgaddr & IO_PAGE_MASK) ^ ((sgaddr + sglen - 1) & IO_PAGE_MASK)) {
-                       unsigned long next_page, diff;
-
-                       next_page = (sgaddr + IO_PAGE_SIZE) & IO_PAGE_MASK;
-                       diff = next_page - sgaddr;
-                       sgaddr += diff;
-                       daddr += diff;
-                       sglen -= diff;
-                       dlen -= diff;
-                       if (dlen > 0)
-                               iopte++;
-                       continue;
-               }
-
-               /* SG wholly consumed within this page. */
-               daddr += sglen;
-               dlen -= sglen;
-
-               if (dlen > 0 && ((daddr & ~IO_PAGE_MASK) == 0))
-                       iopte++;
-
-               sg = sg_next(sg);
-               if (--nents <= 0)
-                       break;
-               sgaddr = (unsigned long) sg_virt(sg);
-               sglen = sg->length;
-       }
-       if (dlen < 0) {
-               /* Transfer overrun, big problems. */
-               printk("verify_one_map: Transfer overrun by %d bytes.\n",
-                      -dlen);
-               nents = -1;
-       } else {
-               /* Advance to next dma_sg implies that the next iopte will
-                * begin it.
-                */
-               iopte++;
-       }
-
-out:
-       *__sg = sg;
-       *__iopte = iopte;
-       return nents;
-}
-
-static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte)
-{
-       struct scatterlist *dma_sg = sg;
-       struct scatterlist *orig_dma_sg = dma_sg;
-       int orig_nents = nents;
-
-       for (;;) {
-               nents = verify_one_map(dma_sg, &sg, nents, &iopte);
-               if (nents <= 0)
-                       break;
-               dma_sg = sg_next(dma_sg);
-               if (dma_sg->dma_length == 0)
-                       break;
-       }
-
-       if (nents > 0) {
-               printk("verify_maps: dma maps consumed by some sgs remain (%d)\n",
-                      nents);
-               return -1;
-       }
-
-       if (nents < 0) {
-               printk("verify_maps: Error, messed up mappings, "
-                      "at sg %d dma_sg %d\n",
-                      (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg));
-               return -1;
-       }
-
-       /* This test passes... */
-       return 0;
-}
-
-void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int npages)
-{
-       struct scatterlist *sg;
-
-       if (verify_lengths(sglist, nents, npages) < 0 ||
-           verify_maps(sglist, nents, iopte) < 0) {
-               int i;
-
-               printk("verify_sglist: Crap, messed up mappings, dumping, iodma at ");
-               printk("%016lx.\n", sglist->dma_address & IO_PAGE_MASK);
-
-               for_each_sg(sglist, sg, nents, i) {
-                       printk("sg(%d): page_addr(%p) off(%x) length(%x) "
-                              "dma_address[%016x] dma_length[%016x]\n",
-                              i,
-                              page_address(sg_page(sg)), sg->offset,
-                              sg->length,
-                              sg->dma_address, sg->dma_length);
-               }
-       }
-
-       /* Seems to be ok */
-}
-#endif
-
-unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents)
-{
-       struct scatterlist *dma_sg = sg;
-       unsigned long prev;
-       u32 dent_addr, dent_len;
-       unsigned int max_seg_size;
-
-       prev  = (unsigned long) sg_virt(sg);
-       prev += (unsigned long) (dent_len = sg->length);
-       dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL));
-       max_seg_size = dma_get_max_seg_size(dev);
-       while (--nents) {
-               unsigned long addr;
-
-               sg = sg_next(sg);
-               addr = (unsigned long) sg_virt(sg);
-               if (! VCONTIG(prev, addr) ||
-                       dent_len + sg->length > max_seg_size) {
-                       dma_sg->dma_address = dent_addr;
-                       dma_sg->dma_length = dent_len;
-                       dma_sg = sg_next(dma_sg);
-
-                       dent_addr = ((dent_addr +
-                                     dent_len +
-                                     (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT);
-                       dent_addr <<= IO_PAGE_SHIFT;
-                       dent_addr += addr & (IO_PAGE_SIZE - 1UL);
-                       dent_len = 0;
-               }
-               dent_len += sg->length;
-               prev = addr + sg->length;
-       }
-       dma_sg->dma_address = dent_addr;
-       dma_sg->dma_length = dent_len;
-
-       if (dma_sg != sg) {
-               dma_sg = sg_next(dma_sg);
-               dma_sg->dma_length = 0;
-       }
-
-       return ((unsigned long) dent_addr +
-               (unsigned long) dent_len +
-               (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT;
-}
index a90d046e8024fd1eb7667d478f2a9f6fd16e245e..4b5cafa2877a4330b6f3f23d46be309009f2a2cc 100644 (file)
  */
 #define IOMMU_PAGE_SHIFT               13
 
+#define SG_ENT_PHYS_ADDRESS(SG)        (__pa(sg_virt((SG))))
+
+static inline unsigned long iommu_num_pages(unsigned long vaddr,
+                                           unsigned long slen)
+{
+       unsigned long npages;
+
+       npages = IO_PAGE_ALIGN(vaddr + slen) - (vaddr & IO_PAGE_MASK);
+       npages >>= IO_PAGE_SHIFT;
+
+       return npages;
+}
+
+static inline unsigned long calc_npages(struct scatterlist *sglist, int nelems)
+{
+       unsigned long i, npages = 0;
+       struct scatterlist *sg;
+
+       for_each_sg(sglist, sg, nelems, i) {
+               unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
+               npages += iommu_num_pages(paddr, sg->length);
+       }
+
+       return npages;
+}
+
 /* You are _strongly_ advised to enable the following debugging code
  * any time you make changes to the sg code below, run it for a while
  * with filesystems mounted read-only before buying the farm... -DaveM
index 5ea2eab1ccdad4d63ea0125db2b65d8a3ad082e9..61baf8dc095e2d2631e7958b4473d419524e47d9 100644 (file)
@@ -365,113 +365,14 @@ static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr,
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-#define SG_ENT_PHYS_ADDRESS(SG)        (__pa(sg_virt((SG))))
-
-static long fill_sg(long entry, struct device *dev,
-                   struct scatterlist *sg,
-                   int nused, int nelems, unsigned long prot)
-{
-       struct scatterlist *dma_sg = sg;
-       unsigned long flags;
-       int i;
-
-       local_irq_save(flags);
-
-       iommu_batch_start(dev, prot, entry);
-
-       for (i = 0; i < nused; i++) {
-               unsigned long pteval = ~0UL;
-               u32 dma_npages;
-
-               dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
-                             dma_sg->dma_length +
-                             ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
-               do {
-                       unsigned long offset;
-                       signed int len;
-
-                       /* If we are here, we know we have at least one
-                        * more page to map.  So walk forward until we
-                        * hit a page crossing, and begin creating new
-                        * mappings from that spot.
-                        */
-                       for (;;) {
-                               unsigned long tmp;
-
-                               tmp = SG_ENT_PHYS_ADDRESS(sg);
-                               len = sg->length;
-                               if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
-                                       pteval = tmp & IO_PAGE_MASK;
-                                       offset = tmp & (IO_PAGE_SIZE - 1UL);
-                                       break;
-                               }
-                               if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
-                                       pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
-                                       offset = 0UL;
-                                       len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
-                                       break;
-                               }
-                               sg = sg_next(sg);
-                               nelems--;
-                       }
-
-                       pteval = (pteval & IOPTE_PAGE);
-                       while (len > 0) {
-                               long err;
-
-                               err = iommu_batch_add(pteval);
-                               if (unlikely(err < 0L))
-                                       goto iommu_map_failed;
-
-                               pteval += IO_PAGE_SIZE;
-                               len -= (IO_PAGE_SIZE - offset);
-                               offset = 0;
-                               dma_npages--;
-                       }
-
-                       pteval = (pteval & IOPTE_PAGE) + len;
-                       sg = sg_next(sg);
-                       nelems--;
-
-                       /* Skip over any tail mappings we've fully mapped,
-                        * adjusting pteval along the way.  Stop when we
-                        * detect a page crossing event.
-                        */
-                       while (nelems &&
-                              (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
-                              (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
-                              ((pteval ^
-                                (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
-                               pteval += sg->length;
-                               sg = sg_next(sg);
-                               nelems--;
-                       }
-                       if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
-                               pteval = ~0UL;
-               } while (dma_npages != 0);
-               dma_sg = sg_next(dma_sg);
-       }
-
-       if (unlikely(iommu_batch_end() < 0L))
-               goto iommu_map_failed;
-
-       local_irq_restore(flags);
-       return 0;
-
-iommu_map_failed:
-       local_irq_restore(flags);
-       return -1L;
-}
-
 static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
                         int nelems, enum dma_data_direction direction)
 {
+       unsigned long flags, npages, i, prot;
+       struct scatterlist *sg;
        struct iommu *iommu;
-       unsigned long flags, npages, prot;
-       u32 dma_base;
-       struct scatterlist *sgtmp;
        long entry, err;
-       int used;
+       u32 dma_base;
 
        /* Fast path single entry scatterlists. */
        if (nelems == 1) {
@@ -489,10 +390,8 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
        if (unlikely(direction == DMA_NONE))
                goto bad;
 
-       /* Step 1: Prepare scatter list. */
-       npages = prepare_sg(dev, sglist, nelems);
+       npages = calc_npages(sglist, nelems);
 
-       /* Step 2: Allocate a cluster and context, if necessary. */
        spin_lock_irqsave(&iommu->lock, flags);
        entry = arena_alloc(&iommu->arena, npages);
        spin_unlock_irqrestore(&iommu->lock, flags);
@@ -503,27 +402,45 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
        dma_base = iommu->page_table_map_base +
                (entry << IO_PAGE_SHIFT);
 
-       /* Step 3: Normalize DMA addresses. */
-       used = nelems;
-
-       sgtmp = sglist;
-       while (used && sgtmp->dma_length) {
-               sgtmp->dma_address += dma_base;
-               sgtmp = sg_next(sgtmp);
-               used--;
-       }
-       used = nelems - used;
-
-       /* Step 4: Create the mappings. */
        prot = HV_PCI_MAP_ATTR_READ;
        if (direction != DMA_TO_DEVICE)
                prot |= HV_PCI_MAP_ATTR_WRITE;
 
-       err = fill_sg(entry, dev, sglist, used, nelems, prot);
+       local_irq_save(flags);
+
+       iommu_batch_start(dev, prot, entry);
+
+       for_each_sg(sglist, sg, nelems, i) {
+               unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
+               unsigned long slen = sg->length;
+               unsigned long this_npages;
+
+               this_npages = iommu_num_pages(paddr, slen);
+
+               sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK);
+               sg->dma_length = slen;
+
+               paddr &= IO_PAGE_MASK;
+               while (this_npages--) {
+                       err = iommu_batch_add(paddr);
+                       if (unlikely(err < 0L)) {
+                               local_irq_restore(flags);
+                               goto iommu_map_failed;
+                       }
+
+                       paddr += IO_PAGE_SIZE;
+                       dma_base += IO_PAGE_SIZE;
+               }
+       }
+
+       err = iommu_batch_end();
+
+       local_irq_restore(flags);
+
        if (unlikely(err < 0L))
                goto iommu_map_failed;
 
-       return used;
+       return nelems;
 
 bad:
        if (printk_ratelimit())
@@ -541,12 +458,11 @@ iommu_map_failed:
 static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
                            int nelems, enum dma_data_direction direction)
 {
+       unsigned long flags, npages;
        struct pci_pbm_info *pbm;
+       u32 devhandle, bus_addr;
        struct iommu *iommu;
-       unsigned long flags, i, npages;
-       struct scatterlist *sg, *sgprv;
        long entry;
-       u32 devhandle, bus_addr;
 
        if (unlikely(direction == DMA_NONE)) {
                if (printk_ratelimit())
@@ -558,16 +474,8 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
        devhandle = pbm->devhandle;
        
        bus_addr = sglist->dma_address & IO_PAGE_MASK;
-       sgprv = NULL;
-       for_each_sg(sglist, sg, nelems, i) {
-               if (sg->dma_length == 0)
-                       break;
-
-               sgprv = sg;
-       }
 
-       npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) -
-                 bus_addr) >> IO_PAGE_SHIFT;
+       npages = calc_npages(sglist, nelems);
 
        entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
index c39944927f1ac7f39f8ddb36671216ca6c2c0162..a8052b76df41b3c15694493cd7e92df7d9b8d1bb 100644 (file)
@@ -46,8 +46,6 @@
 #include <asm/ldc.h>
 #include <asm/hypervisor.h>
 
-extern void calibrate_delay(void);
-
 int sparc64_multi_core __read_mostly;
 
 cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE;
index 60765e314bd8624dfb1dd94329fd2fb0f59ad7f9..8649635d6d74f67e2b184903c3c1d3241fe3c47b 100644 (file)
@@ -277,6 +277,7 @@ EXPORT_SYMBOL(sys_getpid);
 EXPORT_SYMBOL(sys_geteuid);
 EXPORT_SYMBOL(sys_getuid);
 EXPORT_SYMBOL(sys_getegid);
+EXPORT_SYMBOL(sysctl_nr_open);
 EXPORT_SYMBOL(sys_getgid);
 EXPORT_SYMBOL(svr4_getcontext);
 EXPORT_SYMBOL(svr4_setcontext);
index b8058906e7271dc3b593d42c299d638138ea987c..adc62f490f368f494e1543d7d7485f39098ae41b 100644 (file)
@@ -80,7 +80,8 @@ sys_call_table32:
        .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
 /*300*/        .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
        .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
-/*310*/        .word compat_sys_utimensat, compat_sys_signalfd, sys_ni_syscall, sys_eventfd, compat_sys_fallocate
+/*310*/        .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate
+       .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime
 
 #endif /* CONFIG_COMPAT */
 
@@ -152,7 +153,8 @@ sys_call_table:
        .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
        .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .word sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate
+/*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
+       .word sys_timerfd_settime, sys_timerfd_gettime
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -271,6 +273,7 @@ sunos_sys_table:
        .word sunos_nosys, sunos_nosys, sunos_nosys
        .word sunos_nosys
 /*310*/        .word sunos_nosys, sunos_nosys, sunos_nosys
-       .word sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys
 
 #endif
index 4352ee4d8dac32863bd588f47ce91ad5f2d8859c..d204f1ab1d4c25a62a5e01a03b3f8fe1ff4e85bf 100644 (file)
@@ -1707,6 +1707,11 @@ static void __exit rtc_mini_exit(void)
        misc_deregister(&rtc_mini_dev);
 }
 
+int __devinit read_current_timer(unsigned long *timer_val)
+{
+       *timer_val = tick_ops->get_tick();
+       return 0;
+}
 
 module_init(rtc_mini_init);
 module_exit(rtc_mini_exit);
index 523e993ee90ca3b46652376a2b3e792b1b462f7d..e726c45645ff3bc85df870d7eed4613427062133 100644 (file)
@@ -997,7 +997,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
                prom_printf("reserve_bootmem(initrd): base[%llx] size[%lx]\n",
                        initrd_start, initrd_end);
 #endif
-               reserve_bootmem(initrd_start, size);
+               reserve_bootmem(initrd_start, size, BOOTMEM_DEFAULT);
 
                initrd_start += PAGE_OFFSET;
                initrd_end += PAGE_OFFSET;
@@ -1007,7 +1007,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
 #ifdef CONFIG_DEBUG_BOOTMEM
        prom_printf("reserve_bootmem(kernel): base[%lx] size[%lx]\n", kern_base, kern_size);
 #endif
-       reserve_bootmem(kern_base, kern_size);
+       reserve_bootmem(kern_base, kern_size, BOOTMEM_DEFAULT);
        *pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT;
 
        /* Add back in the initmem pages. */
@@ -1024,7 +1024,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
        prom_printf("reserve_bootmem(bootmap): base[%lx] size[%lx]\n",
                    (bootmap_pfn << PAGE_SHIFT), size);
 #endif
-       reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
+       reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size, BOOTMEM_DEFAULT);
 
        for (i = 0; i < pavail_ents; i++) {
                unsigned long start_pfn, end_pfn;
@@ -1489,7 +1489,7 @@ static void __init taint_real_pages(void)
                                        goto do_next_page;
                                }
                        }
-                       reserve_bootmem(old_start, PAGE_SIZE);
+                       reserve_bootmem(old_start, PAGE_SIZE, BOOTMEM_DEFAULT);
 
                do_next_page:
                        old_start += PAGE_SIZE;
index 61be597bf43037d3df41bd85997db373f7cbde61..9311bfe4f2f7e98cf6940782e26cabbbc5b4fd0f 100644 (file)
@@ -624,7 +624,7 @@ asmlinkage int solaris_ulimit(int cmd, int val)
        case 3: /* UL_GMEMLIM */
                return current->signal->rlim[RLIMIT_DATA].rlim_cur;
        case 4: /* UL_GDESLIM */
-               return NR_OPEN;
+               return sysctl_nr_open;
        }
        return -EINVAL;
 }
index a9d32ceabf26e5bed3c6cf2dc2810a2d94e2a07d..f53123c02c2b6b76f9b687bd1f675753d1342633 100644 (file)
@@ -859,7 +859,8 @@ asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
 
        SOLD("entry");
        lock_kernel();
-       if(fd >= NR_OPEN) goto out;
+       if (fd >= sysctl_nr_open)
+               goto out;
 
        fdt = files_fdtable(current->files);
        filp = fdt->fd[fd];
@@ -927,7 +928,8 @@ asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
 
        SOLD("entry");
        lock_kernel();
-       if(fd >= NR_OPEN) goto out;
+       if (fd >= sysctl_nr_open)
+               goto out;
 
        fdt = files_fdtable(current->files);
        filp = fdt->fd[fd];
index 0e429041a117606aa39674aa3d367ac684910a92..5978a25170fb44aa7986be9202abe7527f39787b 100644 (file)
@@ -85,7 +85,8 @@ void __init mach_reserve_bootmem ()
        /* The space between SRAM and SDRAM is filled with duplicate
           images of SRAM.  Prevent the kernel from using them.  */
        reserve_bootmem (SRAM_ADDR + SRAM_SIZE,
-                        SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE));
+                        SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE),
+                        BOOTMEM_DEFAULT);
 }
 
 void mach_gettimeofday (struct timespec *tv)
index 18437bc5c3ad29aa53eb221d0a1595aa7445aac2..b525ecf3aea49c4cd6707f2a8c53e447caf81693 100644 (file)
@@ -116,7 +116,8 @@ void __init mach_reserve_bootmem ()
        if (SDRAM_ADDR < RAM_END && SDRAM_ADDR > RAM_START)
                /* We can't use the space between SRAM and SDRAM, so
                   prevent the kernel from trying.  */
-               reserve_bootmem (SRAM_END, SDRAM_ADDR - SRAM_END);
+               reserve_bootmem(SRAM_END, SDRAM_ADDR - SRAM_END,
+                               BOOTMEM_DEFAULT);
 }
 
 void mach_gettimeofday (struct timespec *tv)
index 9a716f9464218ba269495cd33638930de0d29174..08abf3d5f8df1c33d84bcef6bf1719e4da9358df 100644 (file)
@@ -46,13 +46,15 @@ void __init mach_reserve_bootmem ()
 {
 #ifdef CONFIG_RTE_CB_MULTI
        /* Prevent the kernel from touching the monitor's scratch RAM.  */
-       reserve_bootmem (MON_SCRATCH_ADDR, MON_SCRATCH_SIZE);
+       reserve_bootmem(MON_SCRATCH_ADDR, MON_SCRATCH_SIZE,
+                       BOOTMEM_DEFAULT);
 #endif
 
        /* The space between SRAM and SDRAM is filled with duplicate
           images of SRAM.  Prevent the kernel from using them.  */
        reserve_bootmem (SRAM_ADDR + SRAM_SIZE,
-                        SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE));
+                        SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE),
+                        BOOTMEM_DEFAULT);
 }
 
 void mach_gettimeofday (struct timespec *tv)
index a914f244f494a77c0d7654e4e8473c7e1e06ea24..a0a8456a8430d6349deee2883ad5646ae65a0f70 100644 (file)
@@ -241,15 +241,18 @@ init_bootmem_alloc (unsigned long ram_start, unsigned long ram_len)
        if (kram_end > kram_start)
                /* Reserve the RAM part of the kernel's address space, so it
                   doesn't get allocated.  */
-               reserve_bootmem (kram_start, kram_end - kram_start);
+               reserve_bootmem(kram_start, kram_end - kram_start,
+                               BOOTMEM_DEFAULT);
        
        if (intv_in_ram && !intv_in_kram)
                /* Reserve the interrupt vector space.  */
-               reserve_bootmem (intv_start, intv_end - intv_start);
+               reserve_bootmem(intv_start, intv_end - intv_start,
+                               BOOTMEM_DEFAULT);
 
        if (bootmap >= ram_start && bootmap < ram_end)
                /* Reserve the bootmap space.  */
-               reserve_bootmem (bootmap, bootmap_len);
+               reserve_bootmem(bootmap, bootmap_len,
+                               BOOTMEM_DEFAULT);
 
        /* Reserve the memory used by the root filesystem image if it's
           in RAM.  */
@@ -257,7 +260,8 @@ init_bootmem_alloc (unsigned long ram_start, unsigned long ram_len)
            && (unsigned long)&_root_fs_image_start >= ram_start
            && (unsigned long)&_root_fs_image_start < ram_end)
                reserve_bootmem ((unsigned long)&_root_fs_image_start,
-                                &_root_fs_image_end - &_root_fs_image_start);
+                                &_root_fs_image_end - &_root_fs_image_start,
+                                BOOTMEM_DEFAULT);
 
        /* Let the platform-dependent code reserve some too.  */
        if (mrb)
index 434821187cfccf9c34b32f91f3784113b6b741f6..923c3babd667871843d0e23022b693e534651e30 100644 (file)
@@ -415,7 +415,7 @@ config HPET_TIMER
 
 config HPET_EMULATE_RTC
        def_bool y
-       depends on HPET_TIMER && (RTC=y || RTC=m)
+       depends on HPET_TIMER && (RTC=y || RTC=m || RTC_DRV_CMOS=m || RTC_DRV_CMOS=y)
 
 # Mark as embedded because too many people got it wrong.
 # The code disables itself when not needed.
@@ -631,7 +631,6 @@ config TOSHIBA
 
 config I8K
        tristate "Dell laptop support"
-       depends on X86_32
        ---help---
          This adds a driver to safely access the System Management Mode
          of the CPU on the Dell Inspiron 8000. The System Management Mode
index 2e1e3af28c3a2d5c455b048a330b720a74d1f8bf..fa555148823de98079ced8464fb31a28c25c4063 100644 (file)
@@ -220,9 +220,9 @@ config DEBUG_BOOT_PARAMS
          This option will cause struct boot_params to be exported via debugfs.
 
 config CPA_DEBUG
-       bool "CPA self test code"
+       bool "CPA self-test code"
        depends on DEBUG_KERNEL
        help
-         Do change_page_attr self tests at boot.
+         Do change_page_attr() self-tests every 30 seconds.
 
 endmenu
index e4c12079171b682a5a45bc5d70daedec3536e2aa..58cccb6483b0580d28d935b4692f62b2675f7d02 100644 (file)
@@ -172,8 +172,7 @@ static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file,
        has_dumped = 1;
        current->flags |= PF_DUMPCORE;
        strncpy(dump.u_comm, current->comm, sizeof(current->comm));
-       dump.u_ar0 = (u32)(((unsigned long)(&dump.regs)) -
-                          ((unsigned long)(&dump)));
+       dump.u_ar0 = offsetof(struct user32, regs);
        dump.signal = signr;
        dump_thread32(regs, &dump);
 
index d9313d9adcedd04479a041a11709627032ca3a52..f86a3c4a2669909be340d195a6ee93201c53cdf9 100644 (file)
@@ -637,7 +637,7 @@ void __init early_cpu_init(void)
 }
 
 /* Make sure %fs is initialized properly in idle threads */
-struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
+struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
 {
        memset(regs, 0, sizeof(struct pt_regs));
        regs->fs = __KERNEL_PERCPU;
index a0522735dd9d9298122b5069baabe2bc12c0cda4..5affe91ca1e5964ff9bd309c78c3619f04379c7b 100644 (file)
@@ -827,7 +827,6 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpuf
 
        for (i = 0; i < data->acpi_data.state_count; i++) {
                u32 index;
-               u32 hi = 0, lo = 0;
 
                index = data->acpi_data.states[i].control & HW_PSTATE_MASK;
                if (index > data->max_hw_pstate) {
index 404a6a2d4016c790c6457b966703f8ebdc669dc2..7139b02627034cb3f69482541b62b1102bbe6287 100644 (file)
@@ -83,8 +83,6 @@ static char cyrix_model_mult2[] __cpuinitdata = "12233445";
  * FIXME: our newer udelay uses the tsc. We don't need to frob with SLOP
  */
 
-extern void calibrate_delay(void) __init;
-
 static void __cpuinit check_cx686_slop(struct cpuinfo_x86 *c)
 {
        unsigned long flags;
index 1e27b69a7a0eca1750e4c16dd2470e49ab706112..b6e136f23d3d3219094bc9fdadaeaba048f01b96 100644 (file)
@@ -659,7 +659,7 @@ static __init int amd_special_default_mtrr(void)
  */
 int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
 {
-       unsigned long i, base, size, highest_addr = 0, def, dummy;
+       unsigned long i, base, size, highest_pfn = 0, def, dummy;
        mtrr_type type;
        u64 trim_start, trim_size;
 
@@ -682,28 +682,27 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
                mtrr_if->get(i, &base, &size, &type);
                if (type != MTRR_TYPE_WRBACK)
                        continue;
-               base <<= PAGE_SHIFT;
-               size <<= PAGE_SHIFT;
-               if (highest_addr < base + size)
-                       highest_addr = base + size;
+               if (highest_pfn < base + size)
+                       highest_pfn = base + size;
        }
 
        /* kvm/qemu doesn't have mtrr set right, don't trim them all */
-       if (!highest_addr) {
+       if (!highest_pfn) {
                printk(KERN_WARNING "WARNING: strange, CPU MTRRs all blank?\n");
                WARN_ON(1);
                return 0;
        }
 
-       if ((highest_addr >> PAGE_SHIFT) < end_pfn) {
+       if (highest_pfn < end_pfn) {
                printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
-                       " all of memory, losing %LdMB of RAM.\n",
-                       (((u64)end_pfn << PAGE_SHIFT) - highest_addr) >> 20);
+                       " all of memory, losing %luMB of RAM.\n",
+                       (end_pfn - highest_pfn) >> (20 - PAGE_SHIFT));
 
                WARN_ON(1);
 
                printk(KERN_INFO "update e820 for mtrr\n");
-               trim_start = highest_addr;
+               trim_start = highest_pfn;
+               trim_start <<= PAGE_SHIFT;
                trim_size = end_pfn;
                trim_size <<= PAGE_SHIFT;
                trim_size -= trim_start;
index bea8474744ffb633ad2d367bc478ec8cae3fb962..c7341e81941cc0e7d6863e317953316c2f045392 100644 (file)
@@ -582,7 +582,6 @@ retint_restore_args:        /* return to kernel space */
        TRACE_IRQS_IRETQ
 restore_args:
        RESTORE_ARGS 0,8,0                                              
-iret_label:    
 #ifdef CONFIG_PARAVIRT
        INTERRUPT_RETURN
 #endif
@@ -593,13 +592,22 @@ ENTRY(native_iret)
        .quad native_iret, bad_iret
        .previous
        .section .fixup,"ax"
-       /* force a signal here? this matches i386 behaviour */
-       /* running with kernel gs */
 bad_iret:
-       movq $11,%rdi   /* SIGSEGV */
-       TRACE_IRQS_ON
-       ENABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI))
-       jmp do_exit
+       /*
+        * The iret traps when the %cs or %ss being restored is bogus.
+        * We've lost the original trap vector and error code.
+        * #GPF is the most likely one to get for an invalid selector.
+        * So pretend we completed the iret and took the #GPF in user mode.
+        *
+        * We are now running with the kernel GS after exception recovery.
+        * But error_entry expects us to have user GS to match the user %cs,
+        * so swap back.
+        */
+       pushq $0
+
+       SWAPGS
+       jmp general_protection
+
        .previous
 
        /* edi: workmask, edx: work */
@@ -911,7 +919,7 @@ error_kernelspace:
           iret run with kernel gs again, so don't set the user space flag.
           B stepping K8s sometimes report an truncated RIP for IRET 
           exceptions returning to compat mode. Check for these here too. */
-       leaq iret_label(%rip),%rbp
+       leaq native_iret(%rip),%rbp
        cmpq %rbp,RIP(%rsp) 
        je   error_swapgs
        movl %ebp,%ebp  /* zero extend */
index 4f283ad215ecac483909e1510ddb98e6f37607d0..09b38d539b09deb0874029b2e28fb7d5b7d2418f 100644 (file)
@@ -250,18 +250,13 @@ ENTRY(secondary_startup_64)
        lretq
 
        /* SMP bootup changes these two */
-#ifndef CONFIG_HOTPLUG_CPU
-       .pushsection .init.data
-#endif
+       __CPUINITDATA
        .align  8
-       .globl  initial_code
-initial_code:
+       ENTRY(initial_code)
        .quad   x86_64_start_kernel
-#ifndef CONFIG_HOTPLUG_CPU
-       .popsection
-#endif
-       .globl init_rsp
-init_rsp:
+       __FINITDATA
+
+       ENTRY(init_rsp)
        .quad  init_thread_union+THREAD_SIZE-8
 
 bad_address:
index c1cfd60639d435f2dbe7358570c925e6a2395100..d0b234c9fc318ac0f11a127f9aac87ce7de55dc6 100644 (file)
@@ -151,7 +151,7 @@ NORET_TYPE void machine_kexec(struct kimage *image)
 
 void arch_crash_save_vmcoreinfo(void)
 {
-#ifdef CONFIG_ARCH_DISCONTIGMEM_ENABLE
+#ifdef CONFIG_NUMA
        VMCOREINFO_SYMBOL(node_data);
        VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
 #endif
index a1fef42f8cdbccbd1664cc659c07781a2b82450a..236d2f8f7ddcee15ed6e4575a5895f42845a2d8c 100644 (file)
@@ -234,5 +234,10 @@ NORET_TYPE void machine_kexec(struct kimage *image)
 void arch_crash_save_vmcoreinfo(void)
 {
        VMCOREINFO_SYMBOL(init_level4_pgt);
+
+#ifdef CONFIG_NUMA
+       VMCOREINFO_SYMBOL(node_data);
+       VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
+#endif
 }
 
index 67009cdd5eca194bbf60fb9a7209a1b94550c23b..f349e68e45a0207793432ec794fea8aa441f6f77 100644 (file)
@@ -736,7 +736,8 @@ static int __init smp_scan_config (unsigned long base, unsigned long length)
                        smp_found_config = 1;
                        printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n",
                                mpf, virt_to_phys(mpf));
-                       reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE);
+                       reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE,
+                                       BOOTMEM_DEFAULT);
                        if (mpf->mpf_physptr) {
                                /*
                                 * We cannot access to MPC table to compute
@@ -751,7 +752,8 @@ static int __init smp_scan_config (unsigned long base, unsigned long length)
                                unsigned long end = max_low_pfn * PAGE_SIZE;
                                if (mpf->mpf_physptr + size > end)
                                        size = end - mpf->mpf_physptr;
-                               reserve_bootmem(mpf->mpf_physptr, size);
+                               reserve_bootmem(mpf->mpf_physptr, size,
+                                               BOOTMEM_DEFAULT);
                        }
 
                        mpf_found = mpf;
index 96286df1bb817fff6e314fead079d40c0cb29f6c..702c33efea84dfad40b15d62cd7775958d653979 100644 (file)
@@ -103,9 +103,26 @@ static int set_segment_reg(struct task_struct *task,
        if (invalid_selector(value))
                return -EIO;
 
-       if (offset != offsetof(struct user_regs_struct, gs))
+       /*
+        * For %cs and %ss we cannot permit a null selector.
+        * We can permit a bogus selector as long as it has USER_RPL.
+        * Null selectors are fine for other segment registers, but
+        * we will never get back to user mode with invalid %cs or %ss
+        * and will take the trap in iret instead.  Much code relies
+        * on user_mode() to distinguish a user trap frame (which can
+        * safely use invalid selectors) from a kernel trap frame.
+        */
+       switch (offset) {
+       case offsetof(struct user_regs_struct, cs):
+       case offsetof(struct user_regs_struct, ss):
+               if (unlikely(value == 0))
+                       return -EIO;
+
+       default:
                *pt_regs_access(task_pt_regs(task), offset) = value;
-       else {
+               break;
+
+       case offsetof(struct user_regs_struct, gs):
                task->thread.gs = value;
                if (task == current)
                        /*
@@ -227,12 +244,16 @@ static int set_segment_reg(struct task_struct *task,
                 * Can't actually change these in 64-bit mode.
                 */
        case offsetof(struct user_regs_struct,cs):
+               if (unlikely(value == 0))
+                       return -EIO;
 #ifdef CONFIG_IA32_EMULATION
                if (test_tsk_thread_flag(task, TIF_IA32))
                        task_pt_regs(task)->cs = value;
 #endif
                break;
        case offsetof(struct user_regs_struct,ss):
+               if (unlikely(value == 0))
+                       return -EIO;
 #ifdef CONFIG_IA32_EMULATION
                if (test_tsk_thread_flag(task, TIF_IA32))
                        task_pt_regs(task)->ss = value;
index 3cd7a2dcd4fe729986267ed1c3d2e20d35ab0a0e..6ba33ca8715abc3e925debf55797b0834aee1a38 100644 (file)
@@ -380,19 +380,19 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0367,
 void force_hpet_resume(void)
 {
        switch (force_hpet_resume_type) {
-           case ICH_FORCE_HPET_RESUME:
-               return ich_force_hpet_resume();
-
-           case OLD_ICH_FORCE_HPET_RESUME:
-               return old_ich_force_hpet_resume();
-
-           case VT8237_FORCE_HPET_RESUME:
-               return vt8237_force_hpet_resume();
-
-           case NVIDIA_FORCE_HPET_RESUME:
-               return nvidia_force_hpet_resume();
-
-           default:
+       case ICH_FORCE_HPET_RESUME:
+               ich_force_hpet_resume();
+               return;
+       case OLD_ICH_FORCE_HPET_RESUME:
+               old_ich_force_hpet_resume();
+               return;
+       case VT8237_FORCE_HPET_RESUME:
+               vt8237_force_hpet_resume();
+               return;
+       case NVIDIA_FORCE_HPET_RESUME:
+               nvidia_force_hpet_resume();
+               return;
+       default:
                break;
        }
 }
index 62adc5f20be5bf87cce61b42c17f5aebf367bdd6..d1d8c347cc0b77a05f2c7d90ca1ddaa1d5420e99 100644 (file)
@@ -390,7 +390,7 @@ static void __init reserve_ebda_region(void)
        unsigned int addr;
        addr = get_bios_ebda();
        if (addr)
-               reserve_bootmem(addr, PAGE_SIZE);
+               reserve_bootmem(addr, PAGE_SIZE, BOOTMEM_DEFAULT);
 }
 
 #ifndef CONFIG_NEED_MULTIPLE_NODES
@@ -484,7 +484,8 @@ static void __init reserve_crashkernel(void)
                                        (unsigned long)(total_mem >> 20));
                        crashk_res.start = crash_base;
                        crashk_res.end   = crash_base + crash_size - 1;
-                       reserve_bootmem(crash_base, crash_size);
+                       reserve_bootmem(crash_base, crash_size,
+                                       BOOTMEM_DEFAULT);
                } else
                        printk(KERN_INFO "crashkernel reservation failed - "
                                        "you have to specify a base address\n");
@@ -525,7 +526,7 @@ static void __init reserve_initrd(void)
        }
        if (ramdisk_end <= end_of_lowmem) {
                /* All in lowmem, easy case */
-               reserve_bootmem(ramdisk_image, ramdisk_size);
+               reserve_bootmem(ramdisk_image, ramdisk_size, BOOTMEM_DEFAULT);
                initrd_start = ramdisk_image + PAGE_OFFSET;
                initrd_end = initrd_start+ramdisk_size;
                return;
@@ -536,7 +537,7 @@ static void __init reserve_initrd(void)
 
        /* Note: this includes all the lowmem currently occupied by
           the initrd, we rely on that fact to keep the data intact. */
-       reserve_bootmem(ramdisk_here, ramdisk_size);
+       reserve_bootmem(ramdisk_here, ramdisk_size, BOOTMEM_DEFAULT);
        initrd_start = ramdisk_here + PAGE_OFFSET;
        initrd_end   = initrd_start + ramdisk_size;
 
@@ -606,13 +607,14 @@ void __init setup_bootmem_allocator(void)
         * bootmem allocator with an invalid RAM area.
         */
        reserve_bootmem(__pa_symbol(_text), (PFN_PHYS(min_low_pfn) +
-                        bootmap_size + PAGE_SIZE-1) - __pa_symbol(_text));
+                        bootmap_size + PAGE_SIZE-1) - __pa_symbol(_text),
+                        BOOTMEM_DEFAULT);
 
        /*
         * reserve physical page 0 - it's a special BIOS page on many boxes,
         * enabling clean reboots, SMP operation, laptop functions.
         */
-       reserve_bootmem(0, PAGE_SIZE);
+       reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT);
 
        /* reserve EBDA region, it's a 4K region */
        reserve_ebda_region();
@@ -622,7 +624,7 @@ void __init setup_bootmem_allocator(void)
        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);
+            reserve_bootmem(0xa0000 - 4096, 4096, BOOTMEM_DEFAULT);
 
 #ifdef CONFIG_SMP
        /*
@@ -630,7 +632,7 @@ void __init setup_bootmem_allocator(void)
         * FIXME: Don't need the extra page at 4K, but need to fix
         * trampoline before removing it. (see the GDT stuff)
         */
-       reserve_bootmem(PAGE_SIZE, PAGE_SIZE);
+       reserve_bootmem(PAGE_SIZE, PAGE_SIZE, BOOTMEM_DEFAULT);
 #endif
 #ifdef CONFIG_ACPI_SLEEP
        /*
index c8939dfddfba3c0f7bdd63e3d21d6d38e67712fc..a49f5f734a5e09d68f9fd1859e6c076405fb7059 100644 (file)
@@ -189,7 +189,7 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
        bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
        e820_register_active_regions(0, start_pfn, end_pfn);
        free_bootmem_with_active_regions(0, end_pfn);
-       reserve_bootmem(bootmap, bootmap_size);
+       reserve_bootmem(bootmap, bootmap_size, BOOTMEM_DEFAULT);
 }
 #endif
 
@@ -220,28 +220,35 @@ static inline void copy_edd(void)
 #ifdef CONFIG_KEXEC
 static void __init reserve_crashkernel(void)
 {
-       unsigned long long free_mem;
+       unsigned long long total_mem;
        unsigned long long crash_size, crash_base;
        int ret;
 
-       free_mem =
-               ((unsigned long long)max_low_pfn - min_low_pfn) << PAGE_SHIFT;
+       total_mem = ((unsigned long long)max_low_pfn - min_low_pfn) << PAGE_SHIFT;
 
-       ret = parse_crashkernel(boot_command_line, free_mem,
+       ret = parse_crashkernel(boot_command_line, total_mem,
                        &crash_size, &crash_base);
        if (ret == 0 && crash_size) {
-               if (crash_base > 0) {
-                       printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
-                                       "for crashkernel (System RAM: %ldMB)\n",
-                                       (unsigned long)(crash_size >> 20),
-                                       (unsigned long)(crash_base >> 20),
-                                       (unsigned long)(free_mem >> 20));
-                       crashk_res.start = crash_base;
-                       crashk_res.end   = crash_base + crash_size - 1;
-                       reserve_bootmem(crash_base, crash_size);
-               } else
+               if (crash_base <= 0) {
                        printk(KERN_INFO "crashkernel reservation failed - "
                                        "you have to specify a base address\n");
+                       return;
+               }
+
+               if (reserve_bootmem(crash_base, crash_size,
+                                       BOOTMEM_EXCLUSIVE) < 0) {
+                       printk(KERN_INFO "crashkernel reservation failed - "
+                                       "memory is in use\n");
+                       return;
+               }
+
+               printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
+                               "for crashkernel (System RAM: %ldMB)\n",
+                               (unsigned long)(crash_size >> 20),
+                               (unsigned long)(crash_base >> 20),
+                               (unsigned long)(total_mem >> 20));
+               crashk_res.start = crash_base;
+               crashk_res.end   = crash_base + crash_size - 1;
        }
 }
 #else
index 5787a0c3e2960919f6dc82f0b034a5ba1d19735c..579b9b740c7c79326c079440cda33341b3ba6472 100644 (file)
@@ -202,8 +202,6 @@ valid_k7:
        ;
 }
 
-extern void calibrate_delay(void);
-
 static atomic_t init_deasserted;
 
 static void __cpuinit smp_callin(void)
index 36c100c323aa5d1a01d0fdf2316deeba5c3c37ec..10b8a6f69f84d51348827655903580cdfa6a5e93 100644 (file)
@@ -139,7 +139,6 @@ static int test_NX(void)
         * Until then, don't run them to avoid too many people getting scared
         * by the error message
         */
-#if 0
 
 #ifdef CONFIG_DEBUG_RODATA
        /* Test 3: Check if the .rodata section is executable */
@@ -152,6 +151,7 @@ static int test_NX(void)
        }
 #endif
 
+#if 0
        /* Test 4: Check if the .data section of a module is executable */
        if (test_address(&test_data)) {
                printk(KERN_ERR "test_nx: .data section is executable\n");
index 3cf72977d01292bbea4492568d85277a8ba6680f..b22c01e05a1841d4a3960a2e62a2881ee9c5babc 100644 (file)
@@ -1176,17 +1176,12 @@ void __init trap_init(void)
 #endif
        set_trap_gate(19,&simd_coprocessor_error);
 
+       /*
+        * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
+        * Generate a build-time error if the alignment is wrong.
+        */
+       BUILD_BUG_ON(offsetof(struct task_struct, thread.i387.fxsave) & 15);
        if (cpu_has_fxsr) {
-               /*
-                * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
-                * Generates a compile-time "error: zero width for bit-field" if
-                * the alignment is wrong.
-                */
-               struct fxsrAlignAssert {
-                       int _:!(offsetof(struct task_struct,
-                                       thread.i387.fxsave) & 15);
-               };
-
                printk(KERN_INFO "Enabling fast FPU save and restore... ");
                set_in_cr4(X86_CR4_OSFXSR);
                printk("done.\n");
index aad9d95469dc68dcb25b9fac93b743d44b7d9038..4535e6d147adb11ffb570a9adcb4e08c6d638130 100644 (file)
 
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/timex.h>
 #include <linux/preempt.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/processor.h>
 #include <asm/delay.h>
@@ -63,7 +65,7 @@ void use_tsc_delay(void)
        delay_fn = delay_tsc;
 }
 
-int read_current_timer(unsigned long *timer_val)
+int __devinit read_current_timer(unsigned long *timer_val)
 {
        if (delay_fn == delay_tsc) {
                rdtscl(*timer_val);
index 45cdd3fbd91c514f38e2c2782f7dbc0dcecd8e90..bbc610518516b11c4bdbe1d10dacd29ce41130c6 100644 (file)
 
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/timex.h>
 #include <linux/preempt.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/delay.h>
 #include <asm/msr.h>
@@ -20,7 +22,7 @@
 #include <asm/smp.h>
 #endif
 
-int read_current_timer(unsigned long *timer_value)
+int __devinit read_current_timer(unsigned long *timer_value)
 {
        rdtscll(*timer_value);
        return 0;
index dffa786f61fe1b17c2a3a4b2e00f07d7e3a8bc2f..3cc8eb2f36a995ad57252be8310ece8fcd32327a 100644 (file)
@@ -444,8 +444,6 @@ static __u32 __init setup_trampoline(void)
 static void __init start_secondary(void *unused)
 {
        __u8 cpuid = hard_smp_processor_id();
-       /* external functions not defined in the headers */
-       extern void calibrate_delay(void);
 
        cpu_init();
 
index 04b1d20e2613ca16018424a10e037f68cfa36973..c394ca0720b8d0566f39536b57fc241202c5eb7a 100644 (file)
@@ -391,7 +391,8 @@ unsigned long __init setup_memory(void)
 void __init numa_kva_reserve(void)
 {
        if (kva_pages)
-               reserve_bootmem(PFN_PHYS(kva_start_pfn), PFN_PHYS(kva_pages));
+               reserve_bootmem(PFN_PHYS(kva_start_pfn), PFN_PHYS(kva_pages),
+                               BOOTMEM_DEFAULT);
 }
 
 void __init zone_sizes_init(void)
index ad8b9733d6b3fee4d2f90e2981e54dc2b71299e4..621afb6343dc359d4205a56021658380b1dda427 100644 (file)
@@ -428,6 +428,16 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
 }
 #endif
 
+static int spurious_fault_check(unsigned long error_code, pte_t *pte)
+{
+       if ((error_code & PF_WRITE) && !pte_write(*pte))
+               return 0;
+       if ((error_code & PF_INSTR) && !pte_exec(*pte))
+               return 0;
+
+       return 1;
+}
+
 /*
  * Handle a spurious fault caused by a stale TLB entry.  This allows
  * us to lazily refresh the TLB when increasing the permissions of a
@@ -457,20 +467,21 @@ static int spurious_fault(unsigned long address,
        if (!pud_present(*pud))
                return 0;
 
+       if (pud_large(*pud))
+               return spurious_fault_check(error_code, (pte_t *) pud);
+
        pmd = pmd_offset(pud, address);
        if (!pmd_present(*pmd))
                return 0;
 
+       if (pmd_large(*pmd))
+               return spurious_fault_check(error_code, (pte_t *) pmd);
+
        pte = pte_offset_kernel(pmd, address);
        if (!pte_present(*pte))
                return 0;
 
-       if ((error_code & PF_WRITE) && !pte_write(*pte))
-               return 0;
-       if ((error_code & PF_INSTR) && !pte_exec(*pte))
-               return 0;
-
-       return 1;
+       return spurious_fault_check(error_code, pte);
 }
 
 /*
@@ -947,11 +958,12 @@ void vmalloc_sync_all(void)
        for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
                if (!test_bit(pgd_index(address), insync)) {
                        const pgd_t *pgd_ref = pgd_offset_k(address);
+                       unsigned long flags;
                        struct page *page;
 
                        if (pgd_none(*pgd_ref))
                                continue;
-                       spin_lock(&pgd_lock);
+                       spin_lock_irqsave(&pgd_lock, flags);
                        list_for_each_entry(page, &pgd_list, lru) {
                                pgd_t *pgd;
                                pgd = (pgd_t *)page_address(page) + pgd_index(address);
@@ -960,7 +972,7 @@ void vmalloc_sync_all(void)
                                else
                                        BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
                        }
-                       spin_unlock(&pgd_lock);
+                       spin_unlock_irqrestore(&pgd_lock, flags);
                        set_bit(pgd_index(address), insync);
                }
                if (address == start)
index 3a98d6f724ab69b9ed4d075a0a14895efe482dbc..5fe880fc305d03c90131948bab8c4cd16096e9f9 100644 (file)
@@ -591,10 +591,17 @@ void mark_rodata_ro(void)
        if (end <= start)
                return;
 
-       set_memory_ro(start, (end - start) >> PAGE_SHIFT);
 
        printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
               (end - start) >> 10);
+       set_memory_ro(start, (end - start) >> PAGE_SHIFT);
+
+       /*
+        * The rodata section (but not the kernel text!) should also be
+        * not-executable.
+        */
+       start = ((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
+       set_memory_nx(start, (end - start) >> PAGE_SHIFT);
 
        rodata_test();
 
@@ -637,9 +644,9 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
 
        /* Should check here against the e820 map to avoid double free */
 #ifdef CONFIG_NUMA
-       reserve_bootmem_node(NODE_DATA(nid), phys, len);
+       reserve_bootmem_node(NODE_DATA(nid), phys, len, BOOTMEM_DEFAULT);
 #else
-       reserve_bootmem(phys, len);
+       reserve_bootmem(phys, len, BOOTMEM_DEFAULT);
 #endif
        if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) {
                dma_reserve += len / PAGE_SIZE;
index 5a02bf4c91ec7eac8b9c25da1cf1f666bc2b961f..1aecc658cd7d9f5f89812196cedfe6721229db88 100644 (file)
@@ -238,9 +238,10 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
 
        free_bootmem_with_active_regions(nodeid, end);
 
-       reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size);
+       reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size,
+                       BOOTMEM_DEFAULT);
        reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start,
-                            bootmap_pages<<PAGE_SHIFT);
+                       bootmap_pages<<PAGE_SHIFT, BOOTMEM_DEFAULT);
 #ifdef CONFIG_ACPI_NUMA
        srat_reserve_add_area(nodeid);
 #endif
index 398f3a578dde446e292109a6463409f1b70d3415..ed82016003540ec66ccd7b18157188f6a9d7a5cf 100644 (file)
@@ -5,6 +5,7 @@
  * and compares page tables forwards and afterwards.
  */
 #include <linux/bootmem.h>
+#include <linux/kthread.h>
 #include <linux/random.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
 
+/*
+ * Only print the results of the first pass:
+ */
+static __read_mostly int print = 1;
+
 enum {
-       NTEST                   = 4000,
+       NTEST                   = 400,
 #ifdef CONFIG_X86_64
        LPS                     = (1 << PMD_SHIFT),
 #elif defined(CONFIG_X86_PAE)
@@ -31,7 +37,7 @@ struct split_state {
        long min_exec, max_exec;
 };
 
-static __init int print_split(struct split_state *s)
+static int print_split(struct split_state *s)
 {
        long i, expected, missed = 0;
        int printed = 0;
@@ -82,10 +88,13 @@ static __init int print_split(struct split_state *s)
                                s->max_exec = addr;
                }
        }
-       printk(KERN_INFO
-               "CPA mapping 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n",
-               s->spg, s->lpg, s->gpg, s->exec,
-               s->min_exec != ~0UL ? s->min_exec : 0, s->max_exec, missed);
+       if (print) {
+               printk(KERN_INFO
+                       " 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n",
+                       s->spg, s->lpg, s->gpg, s->exec,
+                       s->min_exec != ~0UL ? s->min_exec : 0,
+                       s->max_exec, missed);
+       }
 
        expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed;
        if (expected != i) {
@@ -96,11 +105,11 @@ static __init int print_split(struct split_state *s)
        return err;
 }
 
-static unsigned long __initdata addr[NTEST];
-static unsigned int __initdata len[NTEST];
+static unsigned long addr[NTEST];
+static unsigned int len[NTEST];
 
 /* Change the global bit on random pages in the direct mapping */
-static __init int exercise_pageattr(void)
+static int pageattr_test(void)
 {
        struct split_state sa, sb, sc;
        unsigned long *bm;
@@ -110,7 +119,8 @@ static __init int exercise_pageattr(void)
        int i, k;
        int err;
 
-       printk(KERN_INFO "CPA exercising pageattr\n");
+       if (print)
+               printk(KERN_INFO "CPA self-test:\n");
 
        bm = vmalloc((max_pfn_mapped + 7) / 8);
        if (!bm) {
@@ -186,7 +196,6 @@ static __init int exercise_pageattr(void)
 
        failed += print_split(&sb);
 
-       printk(KERN_INFO "CPA reverting everything\n");
        for (i = 0; i < NTEST; i++) {
                if (!addr[i])
                        continue;
@@ -214,12 +223,40 @@ static __init int exercise_pageattr(void)
        failed += print_split(&sc);
 
        if (failed) {
-               printk(KERN_ERR "CPA selftests NOT PASSED. Please report.\n");
+               printk(KERN_ERR "NOT PASSED. Please report.\n");
                WARN_ON(1);
+               return -EINVAL;
        } else {
-               printk(KERN_INFO "CPA selftests PASSED\n");
+               if (print)
+                       printk(KERN_INFO "ok.\n");
        }
 
        return 0;
 }
-module_init(exercise_pageattr);
+
+static int do_pageattr_test(void *__unused)
+{
+       while (!kthread_should_stop()) {
+               schedule_timeout_interruptible(HZ*30);
+               if (pageattr_test() < 0)
+                       break;
+               if (print)
+                       print--;
+       }
+       return 0;
+}
+
+static int start_pageattr_test(void)
+{
+       struct task_struct *p;
+
+       p = kthread_create(do_pageattr_test, NULL, "pageattr-test");
+       if (!IS_ERR(p))
+               wake_up_process(p);
+       else
+               WARN_ON(1);
+
+       return 0;
+}
+
+module_init(start_pageattr_test);
index 16ce841f08d6600170a8cf223a80f04cec1376d9..8493c855582bf56a5a36d2e6e64266332c9d26c0 100644 (file)
@@ -167,8 +167,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
        if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext)))
                pgprot_val(forbidden) |= _PAGE_NX;
 
-
-#ifdef CONFIG_DEBUG_RODATA
        /* The .rodata section needs to be read-only */
        if (within(address, (unsigned long)__start_rodata,
                                (unsigned long)__end_rodata))
@@ -179,7 +177,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
        if (within(address, virt_to_highmap(__start_rodata),
                                virt_to_highmap(__end_rodata)))
                pgprot_val(forbidden) |= _PAGE_RW;
-#endif
 
        prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
 
@@ -260,17 +257,6 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
        pgprot_t old_prot, new_prot;
        int level, do_split = 1;
 
-       /*
-        * An Athlon 64 X2 showed hard hangs if we tried to preserve
-        * largepages and changed the PSE entry from RW to RO.
-        *
-        * As AMD CPUs have a long series of erratas in this area,
-        * (and none of the known ones seem to explain this hang),
-        * disable this code until the hang can be debugged:
-        */
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-               return 1;
-
        spin_lock_irqsave(&pgd_lock, flags);
        /*
         * Check for races, another CPU might have split this page
index 65416f843e597b2908d64eee5ae321f1e29d7537..ecd91ea8a8ae66d5f7ecd54de0b907fc65565bd4 100644 (file)
@@ -488,7 +488,8 @@ void __init srat_reserve_add_area(int nodeid)
                printk(KERN_INFO "SRAT: This will cost you %Lu MB of "
                                "pre-allocated memory.\n", (unsigned long long)total_mb);
                reserve_bootmem_node(NODE_DATA(nodeid), nodes_add[nodeid].start,
-                              nodes_add[nodeid].end - nodes_add[nodeid].start);
+                              nodes_add[nodeid].end - nodes_add[nodeid].start,
+                              BOOTMEM_DEFAULT);
        }
 }
 
index 60d29fe0b1bdfd7dac917d5b6ad9f3114acc08e3..8df1e842f6d401d060d077246d97d942c2033cad 100644 (file)
@@ -204,7 +204,7 @@ again:
 }
 
 #ifndef CONFIG_GENERIC_CALIBRATE_DELAY
-void __devinit calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
 {
        loops_per_jiffy = CCOUNT_PER_JIFFY;
        printk("Calibrating delay loop (skipped)... "
index 047e533fcc5ba249977895ea1c3969f6a6b0be2e..0f6282207b3223baf9910332681fd5b3eb98295c 100644 (file)
@@ -35,7 +35,7 @@
  * @src: src page
  * @offset: offset in pages to start transaction
  * @len: length in bytes
- * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
  * @depend_tx: memcpy depends on the result of this transaction
  * @cb_fn: function to call when the memcpy completes
  * @cb_param: parameter to pass to the callback routine
@@ -46,33 +46,29 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
        struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY);
+       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY,
+                                                     &dest, 1, &src, 1, len);
        struct dma_device *device = chan ? chan->device : NULL;
-       int int_en = cb_fn ? 1 : 0;
-       struct dma_async_tx_descriptor *tx = device ?
-               device->device_prep_dma_memcpy(chan, len,
-               int_en) : NULL;
+       struct dma_async_tx_descriptor *tx = NULL;
 
-       if (tx) { /* run the memcpy asynchronously */
-               dma_addr_t addr;
-               enum dma_data_direction dir;
+       if (device) {
+               dma_addr_t dma_dest, dma_src;
+               unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
 
-               pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
-
-               dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-                       DMA_NONE : DMA_FROM_DEVICE;
-
-               addr = dma_map_page(device->dev, dest, dest_offset, len, dir);
-               tx->tx_set_dest(addr, tx, 0);
+               dma_dest = dma_map_page(device->dev, dest, dest_offset, len,
+                                       DMA_FROM_DEVICE);
 
-               dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-                       DMA_NONE : DMA_TO_DEVICE;
+               dma_src = dma_map_page(device->dev, src, src_offset, len,
+                                      DMA_TO_DEVICE);
 
-               addr = dma_map_page(device->dev, src, src_offset, len, dir);
-               tx->tx_set_src(addr, tx, 0);
+               tx = device->device_prep_dma_memcpy(chan, dma_dest, dma_src,
+                                                   len, dma_prep_flags);
+       }
 
+       if (tx) {
+               pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
                async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
-       } else { /* run the memcpy synchronously */
+       } else {
                void *dest_buf, *src_buf;
                pr_debug("%s: (sync) len: %zu\n", __FUNCTION__, len);
 
index 66ef6351202ef9cf0f9ddb162524141b92e8b1cf..09c0e83664bc23f4465cad7b6c477ca76b1d46da 100644 (file)
@@ -35,7 +35,7 @@
  * @val: fill value
  * @offset: offset in pages to start transaction
  * @len: length in bytes
- * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
  * @depend_tx: memset depends on the result of this transaction
  * @cb_fn: function to call when the memcpy completes
  * @cb_param: parameter to pass to the callback routine
@@ -46,24 +46,24 @@ async_memset(struct page *dest, int val, unsigned int offset,
        struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET);
+       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET,
+                                                     &dest, 1, NULL, 0, len);
        struct dma_device *device = chan ? chan->device : NULL;
-       int int_en = cb_fn ? 1 : 0;
-       struct dma_async_tx_descriptor *tx = device ?
-               device->device_prep_dma_memset(chan, val, len,
-                       int_en) : NULL;
+       struct dma_async_tx_descriptor *tx = NULL;
 
-       if (tx) { /* run the memset asynchronously */
-               dma_addr_t dma_addr;
-               enum dma_data_direction dir;
+       if (device) {
+               dma_addr_t dma_dest;
+               unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
 
-               pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
-               dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-                       DMA_NONE : DMA_FROM_DEVICE;
+               dma_dest = dma_map_page(device->dev, dest, offset, len,
+                                       DMA_FROM_DEVICE);
 
-               dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
-               tx->tx_set_dest(dma_addr, tx, 0);
+               tx = device->device_prep_dma_memset(chan, dma_dest, val, len,
+                                                   dma_prep_flags);
+       }
 
+       if (tx) {
+               pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
                async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
        } else { /* run the memset synchronously */
                void *dest_buf;
index bc18cbb8ea79562ce05401a5734d8310cf2ea938..562882189de589587c475b25770ff46b90eac6ac 100644 (file)
@@ -57,8 +57,7 @@ static struct chan_ref_percpu *channel_table[DMA_TX_TYPE_END];
  */
 static spinlock_t async_tx_lock;
 
-static struct list_head
-async_tx_master_list = LIST_HEAD_INIT(async_tx_master_list);
+static LIST_HEAD(async_tx_master_list);
 
 /* async_tx_issue_pending_all - start all transactions on all channels */
 void async_tx_issue_pending_all(void)
@@ -362,13 +361,13 @@ static void __exit async_tx_exit(void)
 }
 
 /**
- * async_tx_find_channel - find a channel to carry out the operation or let
+ * __async_tx_find_channel - find a channel to carry out the operation or let
  *     the transaction execute synchronously
  * @depend_tx: transaction dependency
  * @tx_type: transaction type
  */
 struct dma_chan *
-async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
+__async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
        enum dma_transaction_type tx_type)
 {
        /* see if we can keep the chain on one channel */
@@ -384,7 +383,7 @@ async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
        } else
                return NULL;
 }
-EXPORT_SYMBOL_GPL(async_tx_find_channel);
+EXPORT_SYMBOL_GPL(__async_tx_find_channel);
 #else
 static int __init async_tx_init(void)
 {
index 2575f674dcd5ee226cb2a29f946e27ab9b9b7c1a..2259a4ff15cb9ce7253f4cc5d4f6132586fe762d 100644 (file)
 #include <linux/raid/xor.h>
 #include <linux/async_tx.h>
 
-static void
-do_async_xor(struct dma_async_tx_descriptor *tx, struct dma_device *device,
+/* do_async_xor - dma map the pages and perform the xor with an engine.
+ *     This routine is marked __always_inline so it can be compiled away
+ *     when CONFIG_DMA_ENGINE=n
+ */
+static __always_inline struct dma_async_tx_descriptor *
+do_async_xor(struct dma_device *device,
        struct dma_chan *chan, struct page *dest, struct page **src_list,
        unsigned int offset, unsigned int src_cnt, size_t len,
        enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       dma_addr_t dma_addr;
-       enum dma_data_direction dir;
+       dma_addr_t dma_dest;
+       dma_addr_t *dma_src = (dma_addr_t *) src_list;
+       struct dma_async_tx_descriptor *tx;
        int i;
+       unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
 
        pr_debug("%s: len: %zu\n", __FUNCTION__, len);
 
-       dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-               DMA_NONE : DMA_FROM_DEVICE;
-
-       dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
-       tx->tx_set_dest(dma_addr, tx, 0);
-
-       dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-               DMA_NONE : DMA_TO_DEVICE;
+       dma_dest = dma_map_page(device->dev, dest, offset, len,
+                               DMA_FROM_DEVICE);
 
-       for (i = 0; i < src_cnt; i++) {
-               dma_addr = dma_map_page(device->dev, src_list[i],
-                       offset, len, dir);
-               tx->tx_set_src(dma_addr, tx, i);
+       for (i = 0; i < src_cnt; i++)
+               dma_src[i] = dma_map_page(device->dev, src_list[i], offset,
+                                         len, DMA_TO_DEVICE);
+
+       /* Since we have clobbered the src_list we are committed
+        * to doing this asynchronously.  Drivers force forward progress
+        * in case they can not provide a descriptor
+        */
+       tx = device->device_prep_dma_xor(chan, dma_dest, dma_src, src_cnt, len,
+                                        dma_prep_flags);
+       if (!tx) {
+               if (depend_tx)
+                       dma_wait_for_async_tx(depend_tx);
+
+               while (!tx)
+                       tx = device->device_prep_dma_xor(chan, dma_dest,
+                                                        dma_src, src_cnt, len,
+                                                        dma_prep_flags);
        }
 
        async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
+
+       return tx;
 }
 
 static void
@@ -102,7 +118,7 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
  * @src_cnt: number of source pages
  * @len: length in bytes
  * @flags: ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DEST,
- *     ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ *     ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
  * @depend_tx: xor depends on the result of this transaction.
  * @cb_fn: function to call when the xor completes
  * @cb_param: parameter to pass to the callback routine
@@ -113,14 +129,16 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
        struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR);
+       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR,
+                                                     &dest, 1, src_list,
+                                                     src_cnt, len);
        struct dma_device *device = chan ? chan->device : NULL;
        struct dma_async_tx_descriptor *tx = NULL;
        dma_async_tx_callback _cb_fn;
        void *_cb_param;
        unsigned long local_flags;
        int xor_src_cnt;
-       int i = 0, src_off = 0, int_en;
+       int i = 0, src_off = 0;
 
        BUG_ON(src_cnt <= 1);
 
@@ -140,20 +158,11 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
                                _cb_param = cb_param;
                        }
 
-                       int_en = _cb_fn ? 1 : 0;
-
-                       tx = device->device_prep_dma_xor(
-                               chan, xor_src_cnt, len, int_en);
-
-                       if (tx) {
-                               do_async_xor(tx, device, chan, dest,
-                               &src_list[src_off], offset, xor_src_cnt, len,
-                               local_flags, depend_tx, _cb_fn,
-                               _cb_param);
-                       } else /* fall through */
-                               goto xor_sync;
+                       tx = do_async_xor(device, chan, dest,
+                                         &src_list[src_off], offset,
+                                         xor_src_cnt, len, local_flags,
+                                         depend_tx, _cb_fn, _cb_param);
                } else { /* run the xor synchronously */
-xor_sync:
                        /* in the sync case the dest is an implied source
                         * (assumes the dest is at the src_off index)
                         */
@@ -242,7 +251,7 @@ static int page_is_zero(struct page *p, unsigned int offset, size_t len)
  * @src_cnt: number of source pages
  * @len: length in bytes
  * @result: 0 if sum == 0 else non-zero
- * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
  * @depend_tx: xor depends on the result of this transaction.
  * @cb_fn: function to call when the xor completes
  * @cb_param: parameter to pass to the callback routine
@@ -254,29 +263,36 @@ async_xor_zero_sum(struct page *dest, struct page **src_list,
        struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_ZERO_SUM);
+       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_ZERO_SUM,
+                                                     &dest, 1, src_list,
+                                                     src_cnt, len);
        struct dma_device *device = chan ? chan->device : NULL;
-       int int_en = cb_fn ? 1 : 0;
-       struct dma_async_tx_descriptor *tx = device ?
-               device->device_prep_dma_zero_sum(chan, src_cnt, len, result,
-                       int_en) : NULL;
-       int i;
+       struct dma_async_tx_descriptor *tx = NULL;
 
        BUG_ON(src_cnt <= 1);
 
-       if (tx) {
-               dma_addr_t dma_addr;
-               enum dma_data_direction dir;
+       if (device) {
+               dma_addr_t *dma_src = (dma_addr_t *) src_list;
+               unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
+               int i;
 
                pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
 
-               dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-                       DMA_NONE : DMA_TO_DEVICE;
-
-               for (i = 0; i < src_cnt; i++) {
-                       dma_addr = dma_map_page(device->dev, src_list[i],
-                               offset, len, dir);
-                       tx->tx_set_src(dma_addr, tx, i);
+               for (i = 0; i < src_cnt; i++)
+                       dma_src[i] = dma_map_page(device->dev, src_list[i],
+                                                 offset, len, DMA_TO_DEVICE);
+
+               tx = device->device_prep_dma_zero_sum(chan, dma_src, src_cnt,
+                                                     len, result,
+                                                     dma_prep_flags);
+               if (!tx) {
+                       if (depend_tx)
+                               dma_wait_for_async_tx(depend_tx);
+
+                       while (!tx)
+                               tx = device->device_prep_dma_zero_sum(chan,
+                                       dma_src, src_cnt, len, result,
+                                       dma_prep_flags);
                }
 
                async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
@@ -311,6 +327,16 @@ EXPORT_SYMBOL_GPL(async_xor_zero_sum);
 
 static int __init async_xor_init(void)
 {
+       #ifdef CONFIG_DMA_ENGINE
+       /* To conserve stack space the input src_list (array of page pointers)
+        * is reused to hold the array of dma addresses passed to the driver.
+        * This conversion is only possible when dma_addr_t is less than the
+        * the size of a pointer.  HIGHMEM64G is known to violate this
+        * assumption.
+        */
+       BUILD_BUG_ON(sizeof(dma_addr_t) > sizeof(struct page *));
+       #endif
+
        return 0;
 }
 
index 6affff882cf835bb88f43e0e5aa68951a8e2ac1a..61ac42e1e32bb75816c0c1b0a7dd614cd80f4474 100644 (file)
@@ -224,7 +224,7 @@ static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb)
        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
                                  CRYPTO_ALG_TYPE_MASK);
        if (IS_ERR(alg))
-               return ERR_PTR(PTR_ERR(alg));
+               return ERR_CAST(alg);
 
        inst = ERR_PTR(-EINVAL);
        if (!is_power_of_2(alg->cra_blocksize))
index 074298f2f8e392ef56391db7c2029fe07d1489c2..250425263e00e59fad2b5a11436ce5a02b9dbe41 100644 (file)
@@ -230,7 +230,7 @@ static struct crypto_instance *cryptd_alloc_blkcipher(
        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
                                  CRYPTO_ALG_TYPE_MASK);
        if (IS_ERR(alg))
-               return ERR_PTR(PTR_ERR(alg));
+               return ERR_CAST(alg);
 
        inst = cryptd_alloc_instance(alg, state);
        if (IS_ERR(inst))
@@ -267,7 +267,7 @@ static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
 
        algt = crypto_get_attr_type(tb);
        if (IS_ERR(algt))
-               return ERR_PTR(PTR_ERR(algt));
+               return ERR_CAST(algt);
 
        switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
        case CRYPTO_ALG_TYPE_BLKCIPHER:
index 6310387a872c6c4df4dd538a3d60f25c70391590..a46838e98a71a18de0b4adcdd46a5f65fa556be6 100644 (file)
@@ -128,7 +128,7 @@ static struct crypto_instance *crypto_ecb_alloc(struct rtattr **tb)
        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
                                  CRYPTO_ALG_TYPE_MASK);
        if (IS_ERR(alg))
-               return ERR_PTR(PTR_ERR(alg));
+               return ERR_CAST(alg);
 
        inst = crypto_alloc_instance("ecb", alg);
        if (IS_ERR(inst))
index a1d016a50e7debd10f6b7030f44d598b6eccedb3..b60c3c7aa320ba08548c050f4fc05d231321de61 100644 (file)
@@ -213,7 +213,7 @@ static struct crypto_instance *hmac_alloc(struct rtattr **tb)
        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
                                  CRYPTO_ALG_TYPE_HASH_MASK);
        if (IS_ERR(alg))
-               return ERR_PTR(PTR_ERR(alg));
+               return ERR_CAST(alg);
 
        inst = crypto_alloc_instance("hmac", alg);
        if (IS_ERR(inst))
index 621095db28b354fa314acb44528f514baf026cf5..9d52e580d10a4d34b5117f801f98cf6bd4249b5c 100644 (file)
@@ -241,7 +241,7 @@ static struct crypto_instance *alloc(struct rtattr **tb)
        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
                                  CRYPTO_ALG_TYPE_MASK);
        if (IS_ERR(alg))
-               return ERR_PTR(PTR_ERR(alg));
+               return ERR_CAST(alg);
 
        inst = crypto_alloc_instance("lrw", alg);
        if (IS_ERR(inst))
index fe704775f88ff0fa526a197201c1a751a8535611..d1b8bdfb58551e5b7844ec423f834f468fe9f3f1 100644 (file)
@@ -234,7 +234,7 @@ static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb)
        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
                                  CRYPTO_ALG_TYPE_MASK);
        if (IS_ERR(alg))
-               return ERR_PTR(PTR_ERR(alg));
+               return ERR_CAST(alg);
 
        inst = crypto_alloc_instance("pcbc", alg);
        if (IS_ERR(inst))
index a82959df678c3741f17b9a6bb30bbaf63a540524..86727403e5ab1f0e5e7bbd15f3703046f4390548 100644 (file)
@@ -301,7 +301,7 @@ static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
                                  CRYPTO_ALG_TYPE_MASK);
        if (IS_ERR(alg))
-               return ERR_PTR(PTR_ERR(alg));
+               return ERR_CAST(alg);
 
        switch(alg->cra_blocksize) {
        case 16:
index 27c8d56111c2959b8d7f6cb64b9dccd85cee8a39..29e71bddd6ffdd12420b4749eb88f79fb51ead26 100644 (file)
@@ -679,24 +679,20 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
 
        /* cross check port_map and cap.n_ports */
        if (port_map) {
-               u32 tmp_port_map = port_map;
-               int n_ports = ahci_nr_ports(cap);
+               int map_ports = 0;
 
-               for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
-                       if (tmp_port_map & (1 << i)) {
-                               n_ports--;
-                               tmp_port_map &= ~(1 << i);
-                       }
-               }
+               for (i = 0; i < AHCI_MAX_PORTS; i++)
+                       if (port_map & (1 << i))
+                               map_ports++;
 
-               /* If n_ports and port_map are inconsistent, whine and
-                * clear port_map and let it be generated from n_ports.
+               /* If PI has more ports than n_ports, whine, clear
+                * port_map and let it be generated from n_ports.
                 */
-               if (n_ports || tmp_port_map) {
+               if (map_ports > ahci_nr_ports(cap)) {
                        dev_printk(KERN_WARNING, &pdev->dev,
-                                  "nr_ports (%u) and implemented port map "
-                                  "(0x%x) don't match, using nr_ports\n",
-                                  ahci_nr_ports(cap), port_map);
+                                  "implemented port map (0x%x) contains more "
+                                  "ports than nr_ports (%u), using nr_ports\n",
+                                  port_map, ahci_nr_ports(cap));
                        port_map = 0;
                }
        }
@@ -2201,7 +2197,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct device *dev = &pdev->dev;
        struct ahci_host_priv *hpriv;
        struct ata_host *host;
-       int i, rc;
+       int n_ports, i, rc;
 
        VPRINTK("ENTER\n");
 
@@ -2255,7 +2251,14 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (hpriv->cap & HOST_CAP_PMP)
                pi.flags |= ATA_FLAG_PMP;
 
-       host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
+       /* CAP.NP sometimes indicate the index of the last enabled
+        * port, at other times, that of the last possible port, so
+        * determining the maximum port number requires looking at
+        * both CAP.NP and port_map.
+        */
+       n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
        if (!host)
                return -ENOMEM;
        host->iomap = pcim_iomap_table(pdev);
index 4b99ed0c59bb2cbada622776825725791e05d997..9c2515f67de56c41237ceb20c221a5fa4e5db2a5 100644 (file)
@@ -1603,7 +1603,8 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
  *     Zero on success, or -ERRNO value.
  */
 
-static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit piix_init_one(struct pci_dev *pdev,
+                                  const struct pci_device_id *ent)
 {
        static int printed_version;
        struct device *dev = &pdev->dev;
index 361cf50cbdeab53565f57e3dcc6c84ec64cfd439..3011919f3ec88f0860d39445d596d5f454f604d6 100644 (file)
@@ -4154,8 +4154,6 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        /* NCQ is broken */
        { "Maxtor *",           "BANC*",        ATA_HORKAGE_NONCQ },
        { "Maxtor 7V300F0",     "VA111630",     ATA_HORKAGE_NONCQ },
-       { "HITACHI HDS7250SASUN500G*", NULL,    ATA_HORKAGE_NONCQ },
-       { "HITACHI HDS7225SBSUN250G*", NULL,    ATA_HORKAGE_NONCQ },
        { "ST380817AS",         "3.42",         ATA_HORKAGE_NONCQ },
        { "ST3160023AS",        "3.42",         ATA_HORKAGE_NONCQ },
 
index 938f48a807ebf5369d089b12300b3b7d1644a7ed..408da30594c442564f311deea0dcb62d7f14bc8b 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 
 static int __devinit pata_of_platform_probe(struct of_device *ofdev,
                                            const struct of_device_id *match)
index 224bb6c2030a3e33fd129f4bf92b59fa661517f3..aad7adc6ea564c9f50dbbcf443ce1396fdbf7593 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/ata.h>
 #include <linux/libata.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 
 #define DRV_NAME "pata_platform"
 #define DRV_VERSION "1.2"
index 922d7b2efba8cf50b6d2a1b8bb144630474623e1..efcb66b6cceff96755b886a7aade98c642530e59 100644 (file)
@@ -355,8 +355,8 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
                        ata_port_printk(qc->ap, KERN_ERR,
                                        "s/g len unaligned : 0x%x\n", sg_len);
 
-               if ((num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1)) &&
-                   (qc->n_iter + 1 != qc->n_elem)) {
+               if (num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1) &&
+                   sg_next(sg) != NULL) {
                        VPRINTK("setting indirect prde\n");
                        prd_ptr_to_indirect_ext = prd;
                        prd->dba = cpu_to_le32(indirect_ext_segment_paddr);
index 3c1b5c9027db5a4446a041b3316440c77c1b1468..080b8362f8d63a033a66f7119c5be35f40d4f6de 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/dmapool.h>
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -179,6 +182,8 @@ enum {
 
        HC_MAIN_IRQ_CAUSE_OFS   = 0x1d60,
        HC_MAIN_IRQ_MASK_OFS    = 0x1d64,
+       HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020,
+       HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024,
        PORT0_ERR               = (1 << 0),     /* shift by port # */
        PORT0_DONE              = (1 << 1),     /* shift by port # */
        HC0_IRQ_PEND            = 0x1ff,        /* bits 0-8 = HC0's ports */
@@ -194,11 +199,13 @@ enum {
        TWSI_INT                = (1 << 24),
        HC_MAIN_RSVD            = (0x7f << 25), /* bits 31-25 */
        HC_MAIN_RSVD_5          = (0x1fff << 19), /* bits 31-19 */
+       HC_MAIN_RSVD_SOC        = (0x3fffffb << 6),     /* bits 31-9, 7-6 */
        HC_MAIN_MASKED_IRQS     = (TRAN_LO_DONE | TRAN_HI_DONE |
                                   PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
                                   HC_MAIN_RSVD),
        HC_MAIN_MASKED_IRQS_5   = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
                                   HC_MAIN_RSVD_5),
+       HC_MAIN_MASKED_IRQS_SOC = (PORTS_0_3_COAL_DONE | HC_MAIN_RSVD_SOC),
 
        /* SATAHC registers */
        HC_CFG_OFS              = 0,
@@ -368,6 +375,7 @@ enum chip_type {
        chip_608x,
        chip_6042,
        chip_7042,
+       chip_soc,
 };
 
 /* Command ReQuest Block: 32B */
@@ -424,6 +432,10 @@ struct mv_host_priv {
        u32                     hp_flags;
        struct mv_port_signal   signal[8];
        const struct mv_hw_ops  *ops;
+       int                     n_ports;
+       void __iomem            *base;
+       void __iomem            *main_cause_reg_addr;
+       void __iomem            *main_mask_reg_addr;
        u32                     irq_cause_ofs;
        u32                     irq_mask_ofs;
        u32                     unmask_all_irqs;
@@ -482,6 +494,15 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
 static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
                        unsigned int n_hc);
 static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
+static void mv_soc_enable_leds(struct mv_host_priv *hpriv,
+                                     void __iomem *mmio);
+static void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx,
+                                     void __iomem *mmio);
+static int mv_soc_reset_hc(struct mv_host_priv *hpriv,
+                                 void __iomem *mmio, unsigned int n_hc);
+static void mv_soc_reset_flash(struct mv_host_priv *hpriv,
+                                     void __iomem *mmio);
+static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio);
 static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio);
 static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
                             unsigned int port_no);
@@ -661,6 +682,12 @@ static const struct ata_port_info mv_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
        },
+       {  /* chip_soc */
+               .flags = MV_COMMON_FLAGS | MV_FLAG_SOC,
+               .pio_mask = 0x1f,      /* pio0-4 */
+               .udma_mask = ATA_UDMA6,
+               .port_ops = &mv_iie_ops,
+       },
 };
 
 static const struct pci_device_id mv_pci_tbl[] = {
@@ -711,6 +738,15 @@ static const struct mv_hw_ops mv6xxx_ops = {
        .reset_bus              = mv_reset_pci_bus,
 };
 
+static const struct mv_hw_ops mv_soc_ops = {
+       .phy_errata             = mv6_phy_errata,
+       .enable_leds            = mv_soc_enable_leds,
+       .read_preamp            = mv_soc_read_preamp,
+       .reset_hc               = mv_soc_reset_hc,
+       .reset_flash            = mv_soc_reset_flash,
+       .reset_bus              = mv_soc_reset_bus,
+};
+
 /*
  * Functions
  */
@@ -749,9 +785,15 @@ static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
                (mv_hardport_from_port(port) * MV_PORT_REG_SZ);
 }
 
+static inline void __iomem *mv_host_base(struct ata_host *host)
+{
+       struct mv_host_priv *hpriv = host->private_data;
+       return hpriv->base;
+}
+
 static inline void __iomem *mv_ap_base(struct ata_port *ap)
 {
-       return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
+       return mv_port_base(mv_host_base(ap->host), ap->port_no);
 }
 
 static inline int mv_get_hc_count(unsigned long port_flags)
@@ -1649,16 +1691,21 @@ static void mv_intr_edma(struct ata_port *ap)
  */
 static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
 {
-       void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = hpriv->base;
        void __iomem *hc_mmio = mv_hc_base(mmio, hc);
        u32 hc_irq_cause;
-       int port, port0;
+       int port, port0, last_port;
 
        if (hc == 0)
                port0 = 0;
        else
                port0 = MV_PORTS_PER_HC;
 
+       if (HAS_PCI(host))
+               last_port = port0 + MV_PORTS_PER_HC;
+       else
+               last_port = port0 + hpriv->n_ports;
        /* we'll need the HC success int register in most cases */
        hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
        if (!hc_irq_cause)
@@ -1669,7 +1716,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
        VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
                hc, relevant, hc_irq_cause);
 
-       for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+       for (port = port0; port < port0 + last_port; port++) {
                struct ata_port *ap = host->ports[port];
                struct mv_port_priv *pp = ap->private_data;
                int have_err_bits, hard_port, shift;
@@ -1764,13 +1811,15 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
 static irqreturn_t mv_interrupt(int irq, void *dev_instance)
 {
        struct ata_host *host = dev_instance;
+       struct mv_host_priv *hpriv = host->private_data;
        unsigned int hc, handled = 0, n_hcs;
-       void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+       void __iomem *mmio = hpriv->base;
        u32 irq_stat, irq_mask;
 
        spin_lock(&host->lock);
-       irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
-       irq_mask = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
+
+       irq_stat = readl(hpriv->main_cause_reg_addr);
+       irq_mask = readl(hpriv->main_mask_reg_addr);
 
        /* check the cases where we either have nothing pending or have read
         * a bogus register value which can indicate HW removal or PCI fault
@@ -1827,7 +1876,8 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
 
 static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = ap->host->private_data;
+       void __iomem *mmio = hpriv->base;
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
@@ -1840,7 +1890,8 @@ static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 
 static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = ap->host->private_data;
+       void __iomem *mmio = hpriv->base;
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
@@ -2178,6 +2229,93 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
        writel(m2, port_mmio + PHY_MODE2);
 }
 
+/* TODO: use the generic LED interface to configure the SATA Presence */
+/* & Acitivy LEDs on the board */
+static void mv_soc_enable_leds(struct mv_host_priv *hpriv,
+                                     void __iomem *mmio)
+{
+       return;
+}
+
+static void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx,
+                          void __iomem *mmio)
+{
+       void __iomem *port_mmio;
+       u32 tmp;
+
+       port_mmio = mv_port_base(mmio, idx);
+       tmp = readl(port_mmio + PHY_MODE2);
+
+       hpriv->signal[idx].amps = tmp & 0x700;  /* bits 10:8 */
+       hpriv->signal[idx].pre = tmp & 0xe0;    /* bits 7:5 */
+}
+
+#undef ZERO
+#define ZERO(reg) writel(0, port_mmio + (reg))
+static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
+                                       void __iomem *mmio, unsigned int port)
+{
+       void __iomem *port_mmio = mv_port_base(mmio, port);
+
+       writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
+
+       mv_channel_reset(hpriv, mmio, port);
+
+       ZERO(0x028);            /* command */
+       writel(0x101f, port_mmio + EDMA_CFG_OFS);
+       ZERO(0x004);            /* timer */
+       ZERO(0x008);            /* irq err cause */
+       ZERO(0x00c);            /* irq err mask */
+       ZERO(0x010);            /* rq bah */
+       ZERO(0x014);            /* rq inp */
+       ZERO(0x018);            /* rq outp */
+       ZERO(0x01c);            /* respq bah */
+       ZERO(0x024);            /* respq outp */
+       ZERO(0x020);            /* respq inp */
+       ZERO(0x02c);            /* test control */
+       writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+}
+
+#undef ZERO
+
+#define ZERO(reg) writel(0, hc_mmio + (reg))
+static void mv_soc_reset_one_hc(struct mv_host_priv *hpriv,
+                                      void __iomem *mmio)
+{
+       void __iomem *hc_mmio = mv_hc_base(mmio, 0);
+
+       ZERO(0x00c);
+       ZERO(0x010);
+       ZERO(0x014);
+
+}
+
+#undef ZERO
+
+static int mv_soc_reset_hc(struct mv_host_priv *hpriv,
+                                 void __iomem *mmio, unsigned int n_hc)
+{
+       unsigned int port;
+
+       for (port = 0; port < hpriv->n_ports; port++)
+               mv_soc_reset_hc_port(hpriv, mmio, port);
+
+       mv_soc_reset_one_hc(hpriv, mmio);
+
+       return 0;
+}
+
+static void mv_soc_reset_flash(struct mv_host_priv *hpriv,
+                                     void __iomem *mmio)
+{
+       return;
+}
+
+static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio)
+{
+       return;
+}
+
 static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
                             unsigned int port_no)
 {
@@ -2342,7 +2480,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
 {
        struct ata_port *ap = link->ap;
        struct mv_host_priv *hpriv = ap->host->private_data;
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       void __iomem *mmio = hpriv->base;
 
        mv_stop_dma(ap);
 
@@ -2383,7 +2521,7 @@ static void mv_error_handler(struct ata_port *ap)
 
 static void mv_eh_freeze(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = ap->host->private_data;
        unsigned int hc = (ap->port_no > 3) ? 1 : 0;
        u32 tmp, mask;
        unsigned int shift;
@@ -2397,13 +2535,14 @@ static void mv_eh_freeze(struct ata_port *ap)
        mask = 0x3 << shift;
 
        /* disable assertion of portN err, done events */
-       tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
-       writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS);
+       tmp = readl(hpriv->main_mask_reg_addr);
+       writelfl(tmp & ~mask, hpriv->main_mask_reg_addr);
 }
 
 static void mv_eh_thaw(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = ap->host->private_data;
+       void __iomem *mmio = hpriv->base;
        unsigned int hc = (ap->port_no > 3) ? 1 : 0;
        void __iomem *hc_mmio = mv_hc_base(mmio, hc);
        void __iomem *port_mmio = mv_ap_base(ap);
@@ -2430,8 +2569,8 @@ static void mv_eh_thaw(struct ata_port *ap)
        writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
 
        /* enable assertion of portN err, done events */
-       tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
-       writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS);
+       tmp = readl(hpriv->main_mask_reg_addr);
+       writelfl(tmp | mask, hpriv->main_mask_reg_addr);
 }
 
 /**
@@ -2598,9 +2737,13 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
                        break;
                }
                break;
+       case chip_soc:
+               hpriv->ops = &mv_soc_ops;
+               hp_flags |= MV_HP_ERRATA_60X1C0;
+               break;
 
        default:
-               dev_printk(KERN_ERR, &pdev->dev,
+               dev_printk(KERN_ERR, host->dev,
                           "BUG: invalid board index %u\n", board_idx);
                return 1;
        }
@@ -2633,15 +2776,25 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
 static int mv_init_host(struct ata_host *host, unsigned int board_idx)
 {
        int rc = 0, n_hc, port, hc;
-       void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
        struct mv_host_priv *hpriv = host->private_data;
-
-       /* global interrupt mask */
-       writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
+       void __iomem *mmio = hpriv->base;
 
        rc = mv_chip_id(host, board_idx);
        if (rc)
-               goto done;
+       goto done;
+
+       if (HAS_PCI(host)) {
+               hpriv->main_cause_reg_addr = hpriv->base +
+                 HC_MAIN_IRQ_CAUSE_OFS;
+               hpriv->main_mask_reg_addr = hpriv->base + HC_MAIN_IRQ_MASK_OFS;
+       } else {
+               hpriv->main_cause_reg_addr = hpriv->base +
+                 HC_SOC_MAIN_IRQ_CAUSE_OFS;
+               hpriv->main_mask_reg_addr = hpriv->base +
+                 HC_SOC_MAIN_IRQ_MASK_OFS;
+       }
+       /* global interrupt mask */
+       writel(0, hpriv->main_mask_reg_addr);
 
        n_hc = mv_get_hc_count(host->ports[0]->flags);
 
@@ -2672,13 +2825,15 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
        for (port = 0; port < host->n_ports; port++) {
                struct ata_port *ap = host->ports[port];
                void __iomem *port_mmio = mv_port_base(mmio, port);
-               unsigned int offset = port_mmio - mmio;
 
                mv_port_init(&ap->ioaddr, port_mmio);
 
 #ifdef CONFIG_PCI
-               ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
-               ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+               if (HAS_PCI(host)) {
+                       unsigned int offset = port_mmio - mmio;
+                       ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+                       ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+               }
 #endif
        }
 
@@ -2694,35 +2849,141 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
                writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
        }
 
-       /* Clear any currently outstanding host interrupt conditions */
-       writelfl(0, mmio + hpriv->irq_cause_ofs);
+       if (HAS_PCI(host)) {
+               /* Clear any currently outstanding host interrupt conditions */
+               writelfl(0, mmio + hpriv->irq_cause_ofs);
 
-       /* and unmask interrupt generation for host regs */
-       writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
+               /* and unmask interrupt generation for host regs */
+               writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
+               if (IS_GEN_I(hpriv))
+                       writelfl(~HC_MAIN_MASKED_IRQS_5,
+                                hpriv->main_mask_reg_addr);
+               else
+                       writelfl(~HC_MAIN_MASKED_IRQS,
+                                hpriv->main_mask_reg_addr);
+
+               VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
+                       "PCI int cause/mask=0x%08x/0x%08x\n",
+                       readl(hpriv->main_cause_reg_addr),
+                       readl(hpriv->main_mask_reg_addr),
+                       readl(mmio + hpriv->irq_cause_ofs),
+                       readl(mmio + hpriv->irq_mask_ofs));
+       } else {
+               writelfl(~HC_MAIN_MASKED_IRQS_SOC,
+                        hpriv->main_mask_reg_addr);
+               VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n",
+                       readl(hpriv->main_cause_reg_addr),
+                       readl(hpriv->main_mask_reg_addr));
+       }
+done:
+       return rc;
+}
 
-       if (IS_GEN_I(hpriv))
-               writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
-       else
-               writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
+/**
+ *      mv_platform_probe - handle a positive probe of an soc Marvell
+ *      host
+ *      @pdev: platform device found
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static int mv_platform_probe(struct platform_device *pdev)
+{
+       static int printed_version;
+       const struct mv_sata_platform_data *mv_platform_data;
+       const struct ata_port_info *ppi[] =
+           { &mv_port_info[chip_soc], NULL };
+       struct ata_host *host;
+       struct mv_host_priv *hpriv;
+       struct resource *res;
+       int n_ports, rc;
 
-       VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
-               "PCI int cause/mask=0x%08x/0x%08x\n",
-               readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
-               readl(mmio + HC_MAIN_IRQ_MASK_OFS),
-               readl(mmio + hpriv->irq_cause_ofs),
-               readl(mmio + hpriv->irq_mask_ofs));
+       if (!printed_version++)
+               dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
-done:
-       return rc;
+       /*
+        * Simple resource validation ..
+        */
+       if (unlikely(pdev->num_resources != 2)) {
+               dev_err(&pdev->dev, "invalid number of resources\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Get the register base first
+        */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL)
+               return -EINVAL;
+
+       /* allocate host */
+       mv_platform_data = pdev->dev.platform_data;
+       n_ports = mv_platform_data->n_ports;
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+       hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+
+       if (!host || !hpriv)
+               return -ENOMEM;
+       host->private_data = hpriv;
+       hpriv->n_ports = n_ports;
+
+       host->iomap = NULL;
+       hpriv->base = ioremap(res->start, res->end - res->start + 1);
+       hpriv->base -= MV_SATAHC0_REG_BASE;
+
+       /* initialize adapter */
+       rc = mv_init_host(host, chip_soc);
+       if (rc)
+               return rc;
+
+       dev_printk(KERN_INFO, &pdev->dev,
+                  "slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH,
+                  host->n_ports);
+
+       return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt,
+                                IRQF_SHARED, &mv6_sht);
+}
+
+/*
+ *
+ *      mv_platform_remove    -       unplug a platform interface
+ *      @pdev: platform device
+ *
+ *      A platform bus SATA device has been unplugged. Perform the needed
+ *      cleanup. Also called on module unload for any active devices.
+ */
+static int __devexit mv_platform_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *base = hpriv->base;
+
+       ata_host_detach(host);
+       iounmap(base);
+       return 0;
 }
 
+static struct platform_driver mv_platform_driver = {
+       .probe                  = mv_platform_probe,
+       .remove                 = __devexit_p(mv_platform_remove),
+       .driver                 = {
+                                  .name = DRV_NAME,
+                                  .owner = THIS_MODULE,
+                                 },
+};
+
+
 #ifdef CONFIG_PCI
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int mv_pci_init_one(struct pci_dev *pdev,
+                          const struct pci_device_id *ent);
+
 
 static struct pci_driver mv_pci_driver = {
        .name                   = DRV_NAME,
        .id_table               = mv_pci_tbl,
-       .probe                  = mv_init_one,
+       .probe                  = mv_pci_init_one,
        .remove                 = ata_pci_remove_one,
 };
 
@@ -2828,14 +3089,15 @@ static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
 }
 
 /**
- *      mv_init_one - handle a positive probe of a Marvell host
+ *      mv_pci_init_one - handle a positive probe of a PCI Marvell host
  *      @pdev: PCI device found
  *      @ent: PCI device ID entry for the matched host
  *
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int mv_pci_init_one(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        static int printed_version;
        unsigned int board_idx = (unsigned int)ent->driver_data;
@@ -2855,6 +3117,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!host || !hpriv)
                return -ENOMEM;
        host->private_data = hpriv;
+       hpriv->n_ports = n_ports;
 
        /* acquire resources */
        rc = pcim_enable_device(pdev);
@@ -2867,6 +3130,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
        host->iomap = pcim_iomap_table(pdev);
+       hpriv->base = host->iomap[MV_PRIMARY_BAR];
 
        rc = pci_go_64(pdev);
        if (rc)
@@ -2895,11 +3159,22 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 }
 #endif
 
+static int mv_platform_probe(struct platform_device *pdev);
+static int __devexit mv_platform_remove(struct platform_device *pdev);
+
 static int __init mv_init(void)
 {
        int rc = -ENODEV;
 #ifdef CONFIG_PCI
        rc = pci_register_driver(&mv_pci_driver);
+       if (rc < 0)
+               return rc;
+#endif
+       rc = platform_driver_register(&mv_platform_driver);
+
+#ifdef CONFIG_PCI
+       if (rc < 0)
+               pci_unregister_driver(&mv_pci_driver);
 #endif
        return rc;
 }
@@ -2909,6 +3184,7 @@ static void __exit mv_exit(void)
 #ifdef CONFIG_PCI
        pci_unregister_driver(&mv_pci_driver);
 #endif
+       platform_driver_unregister(&mv_platform_driver);
 }
 
 MODULE_AUTHOR("Brett Russ");
index bfe92a43cf895d4169619298d6f18a037b828a5c..ed5473bf7a0a2005ea5e156cc1eff7cc723ca54d 100644 (file)
@@ -247,6 +247,7 @@ struct nv_adma_port_priv {
        void __iomem            *ctl_block;
        void __iomem            *gen_block;
        void __iomem            *notifier_clear_block;
+       u64                     adma_dma_mask;
        u8                      flags;
        int                     last_issue_ncq;
 };
@@ -715,9 +716,10 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
 {
        struct ata_port *ap = ata_shost_to_port(sdev->host);
        struct nv_adma_port_priv *pp = ap->private_data;
+       struct nv_adma_port_priv *port0, *port1;
+       struct scsi_device *sdev0, *sdev1;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u64 bounce_limit;
-       unsigned long segment_boundary;
+       unsigned long segment_boundary, flags;
        unsigned short sg_tablesize;
        int rc;
        int adma_enable;
@@ -729,6 +731,8 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                /* Not a proper libata device, ignore */
                return rc;
 
+       spin_lock_irqsave(ap->lock, flags);
+
        if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) {
                /*
                 * NVIDIA reports that ADMA mode does not support ATAPI commands.
@@ -737,7 +741,6 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                 * Restrict DMA parameters as required by the legacy interface
                 * when an ATAPI device is connected.
                 */
-               bounce_limit = ATA_DMA_MASK;
                segment_boundary = ATA_DMA_BOUNDARY;
                /* Subtract 1 since an extra entry may be needed for padding, see
                   libata-scsi.c */
@@ -748,7 +751,6 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                adma_enable = 0;
                nv_adma_register_mode(ap);
        } else {
-               bounce_limit = *ap->dev->dma_mask;
                segment_boundary = NV_ADMA_DMA_BOUNDARY;
                sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN;
                adma_enable = 1;
@@ -774,12 +776,49 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
        if (current_reg != new_reg)
                pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg);
 
-       blk_queue_bounce_limit(sdev->request_queue, bounce_limit);
+       port0 = ap->host->ports[0]->private_data;
+       port1 = ap->host->ports[1]->private_data;
+       sdev0 = ap->host->ports[0]->link.device[0].sdev;
+       sdev1 = ap->host->ports[1]->link.device[0].sdev;
+       if ((port0->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
+           (port1->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
+               /** We have to set the DMA mask to 32-bit if either port is in
+                   ATAPI mode, since they are on the same PCI device which is
+                   used for DMA mapping. If we set the mask we also need to set
+                   the bounce limit on both ports to ensure that the block
+                   layer doesn't feed addresses that cause DMA mapping to
+                   choke. If either SCSI device is not allocated yet, it's OK
+                   since that port will discover its correct setting when it
+                   does get allocated.
+                   Note: Setting 32-bit mask should not fail. */
+               if (sdev0)
+                       blk_queue_bounce_limit(sdev0->request_queue,
+                                              ATA_DMA_MASK);
+               if (sdev1)
+                       blk_queue_bounce_limit(sdev1->request_queue,
+                                              ATA_DMA_MASK);
+
+               pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       } else {
+               /** This shouldn't fail as it was set to this value before */
+               pci_set_dma_mask(pdev, pp->adma_dma_mask);
+               if (sdev0)
+                       blk_queue_bounce_limit(sdev0->request_queue,
+                                              pp->adma_dma_mask);
+               if (sdev1)
+                       blk_queue_bounce_limit(sdev1->request_queue,
+                                              pp->adma_dma_mask);
+       }
+
        blk_queue_segment_boundary(sdev->request_queue, segment_boundary);
        blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize);
        ata_port_printk(ap, KERN_INFO,
-               "bounce limit 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
-               (unsigned long long)bounce_limit, segment_boundary, sg_tablesize);
+               "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
+               (unsigned long long)*ap->host->dev->dma_mask,
+               segment_boundary, sg_tablesize);
+
+       spin_unlock_irqrestore(ap->lock, flags);
+
        return rc;
 }
 
@@ -1140,10 +1179,20 @@ static int nv_adma_port_start(struct ata_port *ap)
        void *mem;
        dma_addr_t mem_dma;
        void __iomem *mmio;
+       struct pci_dev *pdev = to_pci_dev(dev);
        u16 tmp;
 
        VPRINTK("ENTER\n");
 
+       /* Ensure DMA mask is set to 32-bit before allocating legacy PRD and
+          pad buffers */
+       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (rc)
+               return rc;
+       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (rc)
+               return rc;
+
        rc = ata_port_start(ap);
        if (rc)
                return rc;
@@ -1159,6 +1208,15 @@ static int nv_adma_port_start(struct ata_port *ap)
        pp->notifier_clear_block = pp->gen_block +
               NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no);
 
+       /* Now that the legacy PRD and padding buffer are allocated we can
+          safely raise the DMA mask to allocate the CPB/APRD table.
+          These are allowed to fail since we store the value that ends up
+          being used to set as the bounce limit in slave_config later if
+          needed. */
+       pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+       pp->adma_dma_mask = *dev->dma_mask;
+
        mem = dmam_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
                                  &mem_dma, GFP_KERNEL);
        if (!mem)
@@ -2417,12 +2475,6 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        hpriv->type = type;
        host->private_data = hpriv;
 
-       /* set 64bit dma masks, may fail */
-       if (type == ADMA) {
-               if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0)
-                       pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
-       }
-
        /* request and iomap NV_MMIO_BAR */
        rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME);
        if (rc)
index 3ef072ff319d28b8514e9ade2fde843d1a23ad2f..30caa033719039c73350fee395c30fd6f374bc24 100644 (file)
@@ -30,8 +30,6 @@
  *  Hardware documentation available under NDA.
  *
  *
- *  To-do list:
- *  - VT6421 PATA support
  *
  */
 
index c5885f5ce0ac9bc44b8bfdb37068360305133ed0..499b003f92782dfc8259791d6f13b4a377f24f5b 100644 (file)
@@ -110,7 +110,7 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
  *
  * Initialize and register the CPU device.
  */
-int __devinit register_cpu(struct cpu *cpu, int num)
+int __cpuinit register_cpu(struct cpu *cpu, int num)
 {
        int error;
        cpu->node_id = cpu_to_node(num);
index 94268c75d04f867e920a39161ed5a4e0c2be21ad..424995073c6b23941fa123b50888b41fcab2148b 100644 (file)
@@ -90,7 +90,7 @@ static struct atari_disk_type {
        unsigned        blocks;         /* total number of blocks */
        unsigned        fdc_speed;      /* fdc_speed setting */
        unsigned        stretch;        /* track doubling ? */
-} disk_type[] = {
+} atari_disk_type[] = {
        { "d360",  9, 720, 0, 0},       /*  0: 360kB diskette */
        { "D360",  9, 720, 0, 1},       /*  1: 360kb in 720k or 1.2MB drive */
        { "D720",  9,1440, 0, 0},       /*  2: 720kb in 720k or 1.2MB drive */
@@ -658,7 +658,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
                        return -EINVAL;
                }
                type = minor2disktype[type].index;
-               UDT = &disk_type[type];
+               UDT = &atari_disk_type[type];
        }
 
        if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
@@ -1064,7 +1064,7 @@ static void fd_rwsec_done1(int status)
               searched for a non-existent sector! */
            !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) {
                if (Probing) {
-                       if (SUDT > disk_type) {
+                       if (SUDT > atari_disk_type) {
                            if (SUDT[-1].blocks > ReqBlock) {
                                /* try another disk type */
                                SUDT--;
@@ -1082,7 +1082,7 @@ static void fd_rwsec_done1(int status)
                } else {        
 /* record not found, but not probing. Maybe stretch wrong ? Restart probing */
                        if (SUD.autoprobe) {
-                               SUDT = disk_type + StartDiskType[DriveType];
+                               SUDT = atari_disk_type + StartDiskType[DriveType];
                                set_capacity(unit[SelectedDrive].disk,
                                                        SUDT->blocks);
                                Probing = 1;
@@ -1421,7 +1421,7 @@ repeat:
        if (type == 0) {
                if (!UDT) {
                        Probing = 1;
-                       UDT = disk_type + StartDiskType[DriveType];
+                       UDT = atari_disk_type + StartDiskType[DriveType];
                        set_capacity(floppy->disk, UDT->blocks);
                        UD.autoprobe = 1;
                }
@@ -1439,7 +1439,7 @@ repeat:
                        goto repeat;
                }
                type = minor2disktype[type].index;
-               UDT = &disk_type[type];
+               UDT = &atari_disk_type[type];
                set_capacity(floppy->disk, UDT->blocks);
                UD.autoprobe = 0;
        }
@@ -1505,7 +1505,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
                        if (minor2disktype[type].drive_types > DriveType)
                                return -ENODEV;
                        type = minor2disktype[type].index;
-                       dtp = &disk_type[type];
+                       dtp = &atari_disk_type[type];
                        if (UD.flags & FTD_MSG)
                            printk (KERN_ERR "floppy%d: found dtp %p name %s!\n",
                                drive, dtp, dtp->name);
@@ -1576,7 +1576,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
                                continue;
                        }
                        setidx = minor2disktype[settype].index;
-                       dtp = &disk_type[setidx];
+                       dtp = &atari_disk_type[setidx];
 
                        /* found matching entry ?? */
                        if (   dtp->blocks  == setprm.size 
index 855ce8e5efbaf3aadca40a5f2405b026b751541f..9715be3f2487c161493f231ee2ef739806cdddc4 100644 (file)
@@ -2630,12 +2630,14 @@ static void do_cciss_request(struct request_queue *q)
                        c->Request.CDB[8] = creq->nr_sectors & 0xff;
                        c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
                } else {
+                       u32 upper32 = upper_32_bits(start_blk);
+
                        c->Request.CDBLen = 16;
                        c->Request.CDB[1]= 0;
-                       c->Request.CDB[2]= (start_blk >> 56) & 0xff;    //MSB
-                       c->Request.CDB[3]= (start_blk >> 48) & 0xff;
-                       c->Request.CDB[4]= (start_blk >> 40) & 0xff;
-                       c->Request.CDB[5]= (start_blk >> 32) & 0xff;
+                       c->Request.CDB[2]= (upper32 >> 24) & 0xff;      //MSB
+                       c->Request.CDB[3]= (upper32 >> 16) & 0xff;
+                       c->Request.CDB[4]= (upper32 >>  8) & 0xff;
+                       c->Request.CDB[5]= upper32 & 0xff;
                        c->Request.CDB[6]= (start_blk >> 24) & 0xff;
                        c->Request.CDB[7]= (start_blk >> 16) & 0xff;
                        c->Request.CDB[8]= (start_blk >>  8) & 0xff;
index b8af22e610dfe4f90ac1b637f0670ec5f9e6bfee..91ebb007416c185587b22ac08e46993f09fcb7dc 100644 (file)
@@ -973,6 +973,10 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
        lo->transfer = xfer->transfer;
        lo->ioctl = xfer->ioctl;
 
+       if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) !=
+            (info->lo_flags & LO_FLAGS_AUTOCLEAR))
+               lo->lo_flags ^= LO_FLAGS_AUTOCLEAR;
+
        lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
        lo->lo_init[0] = info->lo_init[0];
        lo->lo_init[1] = info->lo_init[1];
@@ -1331,6 +1335,10 @@ static int lo_release(struct inode *inode, struct file *file)
 
        mutex_lock(&lo->lo_ctl_mutex);
        --lo->lo_refcnt;
+
+       if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) && !lo->lo_refcnt)
+               loop_clr_fd(lo, inode->i_bdev);
+
        mutex_unlock(&lo->lo_ctl_mutex);
 
        return 0;
index 76096cad798f1c54708a498a90d5eb85eb105f83..8b9549ab4a4e6eafd21b2e38b835618448cf31d9 100644 (file)
@@ -660,7 +660,7 @@ static int pt_open(struct inode *inode, struct file *file)
        pt_identify(tape);
 
        err = -ENODEV;
-       if (!tape->flags & PT_MEDIA)
+       if (!(tape->flags & PT_MEDIA))
                goto out;
 
        err = -EROFS;
index e9de1712e5a0b1b98b8cc1ce95d59d8daf0b615e..674cd66dcabaae261ca0e97c5ab61a1f272b2db5 100644 (file)
@@ -2212,11 +2212,11 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed)
                return ret;
        }
 
-       if (!buf[6] & 0x40) {
+       if (!(buf[6] & 0x40)) {
                printk(DRIVER_NAME": Disc type is not CD-RW\n");
                return 1;
        }
-       if (!buf[6] & 0x4) {
+       if (!(buf[6] & 0x4)) {
                printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
                return 1;
        }
index 82f4eecc8699d19e42e899b043e2c45842cdbcc1..06e23be70904423afc8e6646832eeda664aa5484 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/backing-dev.h>
 #include <linux/blkpg.h>
 #include <linux/writeback.h>
+#include <linux/log2.h>
 
 #include <asm/uaccess.h>
 
@@ -450,7 +451,7 @@ static int __init rd_init(void)
        err = -ENOMEM;
 
        if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
-                       (rd_blocksize & (rd_blocksize-1))) {
+                       !is_power_of_2(rd_blocksize)) {
                printk("RAMDISK: wrong blocksize %d, reverting to defaults\n",
                       rd_blocksize);
                rd_blocksize = BLOCK_SIZE;
index 47e5b40510cb4655cb031ce7470a81c5b7ebf85e..db259e60289b51ca84b46f56f67a741b0c473c16 100644 (file)
@@ -1206,25 +1206,26 @@ int check_for_audio_disc(struct cdrom_device_info * cdi,
        return 0;
 }
 
-/* Admittedly, the logic below could be performed in a nicer way. */
 int cdrom_release(struct cdrom_device_info *cdi, struct file *fp)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
        int opened_for_data;
 
-       cdinfo(CD_CLOSE, "entering cdrom_release\n"); 
+       cdinfo(CD_CLOSE, "entering cdrom_release\n");
 
        if (cdi->use_count > 0)
                cdi->use_count--;
-       if (cdi->use_count == 0)
+
+       if (cdi->use_count == 0) {
                cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
-       if (cdi->use_count == 0)
                cdrom_dvd_rw_close_write(cdi);
-       if (cdi->use_count == 0 &&
-           (cdo->capability & CDC_LOCK) && !keeplocked) {
-               cdinfo(CD_CLOSE, "Unlocking door!\n");
-               cdo->lock_door(cdi, 0);
+
+               if ((cdo->capability & CDC_LOCK) && !keeplocked) {
+                       cdinfo(CD_CLOSE, "Unlocking door!\n");
+                       cdo->lock_door(cdi, 0);
+               }
        }
+
        opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
                !(fp && fp->f_flags & O_NONBLOCK);
 
index be8371ac30869d3f0671e14dfe99594f9d5eda5b..f01ac9a07bf5533a7b8917775aff88f0eb5ff901 100644 (file)
@@ -194,17 +194,6 @@ config MOXA_INTELLIO
          module will be called moxa.
 
 config MOXA_SMARTIO
-       tristate "Moxa SmartIO support (OBSOLETE)"
-       depends on SERIAL_NONSTANDARD
-       help
-         Say Y here if you have a Moxa SmartIO multiport serial card.
-
-         This driver can also be built as a module ( = code which can be
-         inserted in and removed from the running kernel whenever you want).
-         The module will be called mxser. If you want to do that, say M
-         here.
-
-config MOXA_SMARTIO_NEW
        tristate "Moxa SmartIO support v. 2.0"
        depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
        help
@@ -215,7 +204,7 @@ config MOXA_SMARTIO_NEW
          changes finally resulting in PCI probing.
 
          This driver can also be built as a module. The module will be called
-         mxser_new. If you want to do that, say M here.
+         mxser. If you want to do that, say M here.
 
 config ISI
        tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
@@ -276,7 +265,7 @@ config N_HDLC
 
 config RISCOM8
        tristate "SDL RISCom/8 card support"
-       depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+       depends on SERIAL_NONSTANDARD
        help
          This is a driver for the SDL Communications RISCom/8 multiport card,
          which gives you many serial ports. You would need something like
@@ -765,7 +754,7 @@ config JS_RTC
 
 config SGI_DS1286
        tristate "SGI DS1286 RTC support"
-       depends on SGI_IP22
+       depends on SGI_HAS_DS1286
        help
          If you say Y here and create a character special file /dev/rtc with
          major number 10 and minor number 135 using mknod ("man mknod"), you
index 686fabbd85cd3ed08f37183a23cf45e9845b6f09..5407b7615614b8864c6c81c259b04283598eedc1 100644 (file)
@@ -33,7 +33,6 @@ obj-$(CONFIG_MOXA_INTELLIO)   += moxa.o
 obj-$(CONFIG_A2232)            += ser_a2232.o generic_serial.o
 obj-$(CONFIG_ATARI_DSP56K)     += dsp56k.o
 obj-$(CONFIG_MOXA_SMARTIO)     += mxser.o
-obj-$(CONFIG_MOXA_SMARTIO_NEW) += mxser_new.o
 obj-$(CONFIG_COMPUTONE)                += ip2/
 obj-$(CONFIG_RISCOM8)          += riscom8.o
 obj-$(CONFIG_ISI)              += isicom.o
index a297238cd3baa4231e2f1426f6ac737f1bef8f94..3c77c02b5d659e6362017cd8bdc6f4ee115943f6 100644 (file)
@@ -77,7 +77,6 @@ static char *board_desc[] =
 #define ON         1
 
 #define FEPTIMEOUT 200000  
-#define SERIAL_TYPE_NORMAL  1
 #define SERIAL_TYPE_INFO    3
 #define EPCA_EVENT_HANGUP   1
 #define EPCA_MAGIC          0x5c6df104L
index 28607763ae649001d31894bdd1654c470ebc7818..c01e26d9ee5ecfff6d51b7de24e8abf536b86d38 100644 (file)
@@ -111,9 +111,6 @@ static char serial_version[] __initdata = "2.2";
 
 static struct tty_driver *esp_driver;
 
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL     1
-
 /*
  * Serial driver configuration section.  Here are the various options:
  *
@@ -245,17 +242,6 @@ static void rs_start(struct tty_struct *tty)
  * -----------------------------------------------------------------------
  */
 
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static inline void rs_sched_event(struct esp_struct *info,
-                                 int event)
-{
-       info->event |= 1 << event;
-       schedule_work(&info->tqueue);
-}
-
 static DEFINE_SPINLOCK(pio_lock);
 
 static inline struct esp_pio_buffer *get_pio_buffer(void)
@@ -477,7 +463,8 @@ static inline void transmit_chars_pio(struct esp_struct *info,
        }
 
        if (info->xmit_cnt < WAKEUP_CHARS) {
-               rs_sched_event(info, ESP_EVENT_WRITE_WAKEUP);
+               if (info->tty)
+                       tty_wakeup(info->tty);
 
 #ifdef SERIAL_DEBUG_INTR
                printk("THRE...");
@@ -515,7 +502,8 @@ static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
        info->xmit_tail = (info->xmit_tail + dma_bytes) & (ESP_XMIT_SIZE - 1);
 
        if (info->xmit_cnt < WAKEUP_CHARS) {
-               rs_sched_event(info, ESP_EVENT_WRITE_WAKEUP);
+               if (info->tty)
+                       tty_wakeup(info->tty);
 
 #ifdef SERIAL_DEBUG_INTR
                printk("THRE...");
@@ -607,7 +595,7 @@ static inline void check_modem_status(struct esp_struct *info)
 #ifdef SERIAL_DEBUG_OPEN
                        printk("scheduling hangup...");
 #endif
-                       schedule_work(&info->tqueue_hangup);
+                       tty_hangup(info->tty);
                }
        }
 }
@@ -723,41 +711,6 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
  * -------------------------------------------------------------------
  */
 
-static void do_softint(struct work_struct *work)
-{
-       struct esp_struct       *info =
-               container_of(work, struct esp_struct, tqueue);
-       struct tty_struct       *tty;
-       
-       tty = info->tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
-               tty_wakeup(tty);
-       }
-}
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (scheduler tqueue) ->
- *     do_serial_hangup() -> tty->hangup() -> esp_hangup()
- * 
- */
-static void do_serial_hangup(struct work_struct *work)
-{
-       struct esp_struct       *info =
-               container_of(work, struct esp_struct, tqueue_hangup);
-       struct tty_struct       *tty;
-       
-       tty = info->tty;
-       if (tty)
-               tty_hangup(tty);
-}
-
 /*
  * ---------------------------------------------------------------
  * Low level utility subroutines for the serial driver:  routines to
@@ -2041,7 +1994,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                tty->driver->flush_buffer(tty);
        tty_ldisc_flush(tty);
        tty->closing = 0;
-       info->event = 0;
        info->tty = NULL;
 
        if (info->blocked_open) {
@@ -2109,7 +2061,6 @@ static void esp_hangup(struct tty_struct *tty)
        
        rs_flush_buffer(tty);
        shutdown(info);
-       info->event = 0;
        info->count = 0;
        info->flags &= ~ASYNC_NORMAL_ACTIVE;
        info->tty = NULL;
@@ -2495,8 +2446,6 @@ static int __init espserial_init(void)
                info->magic = ESP_MAGIC;
                info->close_delay = 5*HZ/10;
                info->closing_wait = 30*HZ;
-               INIT_WORK(&info->tqueue, do_softint);
-               INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
                info->config.rx_timeout = rx_timeout;
                info->config.flow_on = flow_on;
                info->config.flow_off = flow_off;
index 480fae29c9b2a508305d67e870684136c8f7581e..44160d5ebca06dbcd7e300c9835cbeb1763c1a4c 100644 (file)
@@ -93,7 +93,7 @@ struct hvc_struct {
 };
 
 /* dynamic list of hvc_struct instances */
-static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs);
+static LIST_HEAD(hvc_structs);
 
 /*
  * Protect the list of hvc_struct instances from inserts and removals during
index 3402def22007145a5ffba726bcc3e3b55554b51d..786d518e947752a56079227111cb322a2de7700e 100644 (file)
@@ -306,7 +306,7 @@ struct hvcs_struct {
 /* Required to back map a kref to its containing object */
 #define from_kref(k) container_of(k, struct hvcs_struct, kref)
 
-static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs);
+static LIST_HEAD(hvcs_structs);
 static DEFINE_SPINLOCK(hvcs_structs_lock);
 
 static void hvcs_unthrottle(struct tty_struct *tty);
index 868e39fd42e49779e494d8c96d097c700ab2d0b2..f7feae4ebb5e9981e7f730f637a2b1e54f5cc767 100644 (file)
@@ -42,6 +42,8 @@ enum {
        VIA_STRFILT_ENABLE      = (1 << 14),
        VIA_RAWBITS_ENABLE      = (1 << 13),
        VIA_RNG_ENABLE          = (1 << 6),
+       VIA_NOISESRC1           = (1 << 8),
+       VIA_NOISESRC2           = (1 << 9),
        VIA_XSTORE_CNT_MASK     = 0x0F,
 
        VIA_RNG_CHUNK_8         = 0x00, /* 64 rand bits, 64 stored bits */
@@ -119,6 +121,7 @@ static int via_rng_data_read(struct hwrng *rng, u32 *data)
 
 static int via_rng_init(struct hwrng *rng)
 {
+       struct cpuinfo_x86 *c = &cpu_data(0);
        u32 lo, hi, old_lo;
 
        /* Control the RNG via MSR.  Tread lightly and pay very close
@@ -134,6 +137,17 @@ static int via_rng_init(struct hwrng *rng)
        lo &= ~VIA_XSTORE_CNT_MASK;
        lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
        lo |= VIA_RNG_ENABLE;
+       lo |= VIA_NOISESRC1;
+
+       /* Enable secondary noise source on CPUs where it is present. */
+
+       /* Nehemiah stepping 8 and higher */
+       if ((c->x86_model == 9) && (c->x86_mask > 7))
+               lo |= VIA_NOISESRC2;
+
+       /* Esther */
+       if (c->x86_model >= 10)
+               lo |= VIA_NOISESRC2;
 
        if (lo != old_lo)
                wrmsr(MSR_VIA_RNG, lo, hi);
index 30e564516422edd31d42996d520c2fdb6bb7206b..8609b8236c67d42562ada21812b3c757534166b6 100644 (file)
@@ -113,6 +113,33 @@ static int i8k_smm(struct smm_regs *regs)
        int rc;
        int eax = regs->eax;
 
+#if defined(CONFIG_X86_64)
+       asm("pushq %%rax\n\t"
+               "movl 0(%%rax),%%edx\n\t"
+               "pushq %%rdx\n\t"
+               "movl 4(%%rax),%%ebx\n\t"
+               "movl 8(%%rax),%%ecx\n\t"
+               "movl 12(%%rax),%%edx\n\t"
+               "movl 16(%%rax),%%esi\n\t"
+               "movl 20(%%rax),%%edi\n\t"
+               "popq %%rax\n\t"
+               "out %%al,$0xb2\n\t"
+               "out %%al,$0x84\n\t"
+               "xchgq %%rax,(%%rsp)\n\t"
+               "movl %%ebx,4(%%rax)\n\t"
+               "movl %%ecx,8(%%rax)\n\t"
+               "movl %%edx,12(%%rax)\n\t"
+               "movl %%esi,16(%%rax)\n\t"
+               "movl %%edi,20(%%rax)\n\t"
+               "popq %%rdx\n\t"
+               "movl %%edx,0(%%rax)\n\t"
+               "lahf\n\t"
+               "shrl $8,%%eax\n\t"
+               "andl $1,%%eax\n"
+               :"=a"(rc)
+               :    "a"(regs)
+               :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
+#else
        asm("pushl %%eax\n\t"
            "movl 0(%%eax),%%edx\n\t"
            "push %%edx\n\t"
@@ -137,7 +164,7 @@ static int i8k_smm(struct smm_regs *regs)
            "andl $1,%%eax\n":"=a"(rc)
            :    "a"(regs)
            :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
-
+#endif
        if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
                return -EINVAL;
 
@@ -439,6 +466,20 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
                },
        },
+       {       /* UK Inspiron 6400  */
+               .ident = "Dell Inspiron 3",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MM061"),
+               },
+       },
+       {
+               .ident = "Dell Inspiron 3",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MP061"),
+               },
+       },
        { }
 };
 
index 0f49ccf02a7fea974440587b337e60f015740e6f..b1d6cad84282e3960f974c9d41df0a4ed8c64500 100644 (file)
@@ -153,9 +153,6 @@ static char *pcVersion = "1.2.14";
 static char *pcDriver_name   = "ip2";
 static char *pcIpl              = "ip2ipl";
 
-/* Serial subtype definitions */
-#define SERIAL_TYPE_NORMAL    1
-
 // cheezy kludge or genius - you decide?
 int ip2_loadmain(int *, int *, unsigned char *, int);
 static unsigned char *Fip_firmware;
index 932264a657d0da57a0567f428d88d07e01445b5a..86e6538a77b05835b352001d170dba5335be284b 100644 (file)
@@ -46,8 +46,8 @@
 #include <asm/sn/sn0/hub.h>
 #include <asm/sn/sn_private.h>
 
-static int rtc_ioctl(struct inode *inode, struct file *file,
-                    unsigned int cmd, unsigned long arg);
+static long rtc_ioctl(struct file *filp, unsigned int cmd,
+                       unsigned long arg);
 
 static int rtc_read_proc(char *page, char **start, off_t off,
                          int count, int *eof, void *data);
@@ -75,8 +75,7 @@ static unsigned long epoch = 1970;    /* year corresponding to 0x00   */
 static const unsigned char days_in_mo[] =
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                    unsigned long arg)
+static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 
        struct rtc_time wtime;
@@ -197,7 +196,7 @@ static int rtc_release(struct inode *inode, struct file *file)
 
 static const struct file_operations rtc_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = rtc_ioctl,
+       .unlocked_ioctl = rtc_ioctl,
        .open           = rtc_open,
        .release        = rtc_release,
 };
index 5dc1265ce1d5b288c7049c9ecb305e72d223f618..32b2b22996dc34efc189ccc71b5cdc2b6b3b4ba2 100644 (file)
@@ -365,12 +365,12 @@ static struct device_driver ipmidriver = {
 };
 static DEFINE_MUTEX(ipmidriver_mutex);
 
-static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
+static LIST_HEAD(ipmi_interfaces);
 static DEFINE_MUTEX(ipmi_interfaces_mutex);
 
 /* List of watchers that want to know when smi's are added and
    deleted. */
-static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
+static LIST_HEAD(smi_watchers);
 static DEFINE_MUTEX(smi_watchers_mutex);
 
 
@@ -441,7 +441,7 @@ struct watcher_entry {
 int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
 {
        ipmi_smi_t intf;
-       struct list_head to_deliver = LIST_HEAD_INIT(to_deliver);
+       LIST_HEAD(to_deliver);
        struct watcher_entry *e, *e2;
 
        mutex_lock(&smi_watchers_mutex);
index 1f27be1ec3d4c1ddf36bccb67cb96c2244683f14..c645455c3fd1552ed9f7932bd28dabb7f963280d 100644 (file)
@@ -627,7 +627,6 @@ static int  stli_initopen(struct stlibrd *brdp, struct stliport *portp);
 static int     stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
 static int     stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
 static int     stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
-static void    stli_dohangup(struct work_struct *);
 static int     stli_setport(struct stliport *portp);
 static int     stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
@@ -1823,25 +1822,6 @@ static void stli_start(struct tty_struct *tty)
 
 /*****************************************************************************/
 
-/*
- *     Scheduler called hang up routine. This is called from the scheduler,
- *     not direct from the driver "poll" routine. We can't call it there
- *     since the real local hangup code will enable/disable the board and
- *     other things that we can't do while handling the poll. Much easier
- *     to deal with it some time later (don't really care when, hangups
- *     aren't that time critical).
- */
-
-static void stli_dohangup(struct work_struct *ugly_api)
-{
-       struct stliport *portp = container_of(ugly_api, struct stliport, tqhangup);
-       if (portp->tty != NULL) {
-               tty_hangup(portp->tty);
-       }
-}
-
-/*****************************************************************************/
-
 /*
  *     Hangup this port. This is pretty much like closing the port, only
  *     a little more brutal. No waiting for data to drain. Shutdown the
@@ -2405,7 +2385,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
                            ((portp->sigs & TIOCM_CD) == 0)) {
                                if (portp->flags & ASYNC_CHECK_CD) {
                                        if (tty)
-                                               schedule_work(&portp->tqhangup);
+                                               tty_hangup(tty);
                                }
                        }
                }
@@ -2733,7 +2713,6 @@ static int stli_initports(struct stlibrd *brdp)
                portp->baud_base = STL_BAUDBASE;
                portp->close_delay = STL_CLOSEDELAY;
                portp->closing_wait = 30 * HZ;
-               INIT_WORK(&portp->tqhangup, stli_dohangup);
                init_waitqueue_head(&portp->open_wait);
                init_waitqueue_head(&portp->close_wait);
                init_waitqueue_head(&portp->raw_wait);
index 81674d7c56c7e74c655e62bb86f2d20cc350aae3..60ac642752bea4441604515513efa160d6e8c73f 100644 (file)
@@ -312,7 +312,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf,
        if (copy_size > LP_BUFFER_SIZE)
                copy_size = LP_BUFFER_SIZE;
 
-       if (down_interruptible (&lp_table[minor].port_mutex))
+       if (mutex_lock_interruptible(&lp_table[minor].port_mutex))
                return -EINTR;
 
        if (copy_from_user (kbuf, buf, copy_size)) {
@@ -399,7 +399,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf,
                lp_release_parport (&lp_table[minor]);
        }
 out_unlock:
-       up (&lp_table[minor].port_mutex);
+       mutex_unlock(&lp_table[minor].port_mutex);
 
        return retv;
 }
@@ -421,7 +421,7 @@ static ssize_t lp_read(struct file * file, char __user * buf,
        if (count > LP_BUFFER_SIZE)
                count = LP_BUFFER_SIZE;
 
-       if (down_interruptible (&lp_table[minor].port_mutex))
+       if (mutex_lock_interruptible(&lp_table[minor].port_mutex))
                return -EINTR;
 
        lp_claim_parport_or_block (&lp_table[minor]);
@@ -479,7 +479,7 @@ static ssize_t lp_read(struct file * file, char __user * buf,
        if (retval > 0 && copy_to_user (buf, kbuf, retval))
                retval = -EFAULT;
 
-       up (&lp_table[minor].port_mutex);
+       mutex_unlock(&lp_table[minor].port_mutex);
 
        return retval;
 }
@@ -888,7 +888,7 @@ static int __init lp_init (void)
                lp_table[i].last_error = 0;
                init_waitqueue_head (&lp_table[i].waitq);
                init_waitqueue_head (&lp_table[i].dataq);
-               init_MUTEX (&lp_table[i].port_mutex);
+               mutex_init(&lp_table[i].port_mutex);
                lp_table[i].timeout = 10 * HZ;
        }
 
index 3c5802ae17164c5f8d2335454afd9ad1b46de0eb..f4716ad7348ae7185bdba2a35379b9a68fd37a63 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/device.h>
 #include <linux/mm.h>
 #include <linux/uio.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -281,7 +282,7 @@ static inline int mbcs_algo_start(struct mbcs_soft *soft)
        void *mmr_base = soft->mmr_base;
        union cm_control cm_control;
 
-       if (down_interruptible(&soft->algolock))
+       if (mutex_lock_interruptible(&soft->algolock))
                return -ERESTARTSYS;
 
        atomic_set(&soft->algo_done, 0);
@@ -298,7 +299,7 @@ static inline int mbcs_algo_start(struct mbcs_soft *soft)
        cm_control.alg_go = 1;
        MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
 
-       up(&soft->algolock);
+       mutex_unlock(&soft->algolock);
 
        return 0;
 }
@@ -309,7 +310,7 @@ do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr,
 {
        int rv = 0;
 
-       if (down_interruptible(&soft->dmawritelock))
+       if (mutex_lock_interruptible(&soft->dmawritelock))
                return -ERESTARTSYS;
 
        atomic_set(&soft->dmawrite_done, 0);
@@ -335,7 +336,7 @@ do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr,
        *off += len;
 
 dmawrite_exit:
-       up(&soft->dmawritelock);
+       mutex_unlock(&soft->dmawritelock);
 
        return rv;
 }
@@ -346,7 +347,7 @@ do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr,
 {
        int rv = 0;
 
-       if (down_interruptible(&soft->dmareadlock))
+       if (mutex_lock_interruptible(&soft->dmareadlock))
                return -ERESTARTSYS;
 
        atomic_set(&soft->dmawrite_done, 0);
@@ -371,7 +372,7 @@ do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr,
        *off += len;
 
 dmaread_exit:
-       up(&soft->dmareadlock);
+       mutex_unlock(&soft->dmareadlock);
 
        return rv;
 }
@@ -762,9 +763,9 @@ static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
        init_waitqueue_head(&soft->dmaread_queue);
        init_waitqueue_head(&soft->algo_queue);
 
-       init_MUTEX(&soft->dmawritelock);
-       init_MUTEX(&soft->dmareadlock);
-       init_MUTEX(&soft->algolock);
+       mutex_init(&soft->dmawritelock);
+       mutex_init(&soft->dmareadlock);
+       mutex_init(&soft->algolock);
 
        mbcs_getdma_init(&soft->getdma);
        mbcs_putdma_init(&soft->putdma);
index c9905a3c3353a06b94b18a48d8b29ca8a281e136..ba671589f4cba31716a0b1ac4f505e39003b5626 100644 (file)
@@ -537,9 +537,9 @@ struct mbcs_soft {
        atomic_t dmawrite_done;
        atomic_t dmaread_done;
        atomic_t algo_done;
-       struct semaphore dmawritelock;
-       struct semaphore dmareadlock;
-       struct semaphore algolock;
+       struct mutex dmawritelock;
+       struct mutex dmareadlock;
+       struct mutex algolock;
 };
 
 static int mbcs_open(struct inode *ip, struct file *fp);
index fd0abef7ee0867dfb86ccc0958e0a1c64402e947..68c2e923469195295ed74c028eb360e2588e9a19 100644 (file)
@@ -1,43 +1,25 @@
 /*
  *          mxser.c  -- MOXA Smartio/Industio family multiport serial driver.
  *
- *      Copyright (C) 1999-2001  Moxa Technologies (support@moxa.com.tw).
+ *      Copyright (C) 1999-2006  Moxa Technologies (support@moxa.com).
+ *     Copyright (C) 2006-2008  Jiri Slaby <jirislaby@gmail.com>
  *
- *      This code is loosely based on the Linux serial driver, written by
- *      Linus Torvalds, Theodore T'so and others.
+ *      This code is loosely based on the 1.8 moxa driver which is based on
+ *     Linux serial driver, written by Linus Torvalds, Theodore T'so and
+ *     others.
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
  *      the Free Software Foundation; either version 2 of the License, or
  *      (at your option) any later version.
  *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *     Original release        10/26/00
- *
- *     02/06/01        Support MOXA Industio family boards.
- *     02/06/01        Support TIOCGICOUNT.
- *     02/06/01        Fix the problem for connecting to serial mouse.
- *     02/06/01        Fix the problem for H/W flow control.
- *     02/06/01        Fix the compling warning when CONFIG_PCI
- *                     don't be defined.
- *
  *     Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
  *     <alan@redhat.com>. The original 1.8 code is available on www.moxa.com.
  *     - Fixed x86_64 cleanness
  *     - Fixed sleep with spinlock held in mxser_send_break
  */
 
-
 #include <linux/module.h>
-#include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 
 #include "mxser.h"
 
-#define        MXSER_VERSION   "1.8"
+#define        MXSER_VERSION   "2.0.3"         /* 1.11 */
 #define        MXSERMAJOR       174
 #define        MXSERCUMAJOR     175
 
-#define        MXSER_EVENT_TXLOW       1
-#define        MXSER_EVENT_HANGUP      2
-
 #define MXSER_BOARDS           4       /* Max. boards */
-#define MXSER_PORTS            32      /* Max. ports */
 #define MXSER_PORTS_PER_BOARD  8       /* Max. ports per board */
-#define MXSER_ISR_PASS_LIMIT   256
+#define MXSER_PORTS            (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
+#define MXSER_ISR_PASS_LIMIT   100
 
 #define        MXSER_ERR_IOADDR        -1
 #define        MXSER_ERR_IRQ           -2
 #define        MXSER_ERR_IRQ_CONFLIT   -3
 #define        MXSER_ERR_VECTOR        -4
 
-#define SERIAL_TYPE_NORMAL     1
-#define SERIAL_TYPE_CALLOUT    2
+/*CheckIsMoxaMust return value*/
+#define MOXA_OTHER_UART                0x00
+#define MOXA_MUST_MU150_HWID   0x01
+#define MOXA_MUST_MU860_HWID   0x02
 
 #define WAKEUP_CHARS           256
 
 #define UART_MCR_AFE           0x20
 #define UART_LSR_SPECIAL       0x1E
 
+#define PCI_DEVICE_ID_CB108    0x1080
+#define PCI_DEVICE_ID_CB114    0x1142
+#define PCI_DEVICE_ID_CP114UL  0x1143
+#define PCI_DEVICE_ID_CB134I   0x1341
+#define PCI_DEVICE_ID_CP138U   0x1380
+#define PCI_DEVICE_ID_POS104UL 0x1044
 
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED)
 
 #define C168_ASIC_ID    1
 #define C104_ASIC_ID    2
 #define CI134_ASIC_ID  3
 #define CI104J_ASIC_ID  5
 
-enum {
-       MXSER_BOARD_C168_ISA = 1,
-       MXSER_BOARD_C104_ISA,
-       MXSER_BOARD_CI104J,
-       MXSER_BOARD_C168_PCI,
-       MXSER_BOARD_C104_PCI,
-       MXSER_BOARD_C102_ISA,
-       MXSER_BOARD_CI132,
-       MXSER_BOARD_CI134,
-       MXSER_BOARD_CP132,
-       MXSER_BOARD_CP114,
-       MXSER_BOARD_CT114,
-       MXSER_BOARD_CP102,
-       MXSER_BOARD_CP104U,
-       MXSER_BOARD_CP168U,
-       MXSER_BOARD_CP132U,
-       MXSER_BOARD_CP134U,
-       MXSER_BOARD_CP104JU,
-       MXSER_BOARD_RC7000,
-       MXSER_BOARD_CP118U,
-       MXSER_BOARD_CP102UL,
-       MXSER_BOARD_CP102U,
-};
-
-static char *mxser_brdname[] = {
-       "C168 series",
-       "C104 series",
-       "CI-104J series",
-       "C168H/PCI series",
-       "C104H/PCI series",
-       "C102 series",
-       "CI-132 series",
-       "CI-134 series",
-       "CP-132 series",
-       "CP-114 series",
-       "CT-114 series",
-       "CP-102 series",
-       "CP-104U series",
-       "CP-168U series",
-       "CP-132U series",
-       "CP-134U series",
-       "CP-104JU series",
-       "Moxa UC7000 Serial",
-       "CP-118U series",
-       "CP-102UL series",
-       "CP-102U series",
-};
-
-static int mxser_numports[] = {
-       8,                      /* C168-ISA */
-       4,                      /* C104-ISA */
-       4,                      /* CI104J */
-       8,                      /* C168-PCI */
-       4,                      /* C104-PCI */
-       2,                      /* C102-ISA */
-       2,                      /* CI132 */
-       4,                      /* CI134 */
-       2,                      /* CP132 */
-       4,                      /* CP114 */
-       4,                      /* CT114 */
-       2,                      /* CP102 */
-       4,                      /* CP104U */
-       8,                      /* CP168U */
-       2,                      /* CP132U */
-       4,                      /* CP134U */
-       4,                      /* CP104JU */
-       8,                      /* RC7000 */
-       8,                      /* CP118U */
-       2,                      /* CP102UL */
-       2,                      /* CP102U */
-};
-
-#define UART_TYPE_NUM  2
-
-static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
-       MOXA_MUST_MU150_HWID,
-       MOXA_MUST_MU860_HWID
-};
+#define MXSER_HIGHBAUD 1
+#define MXSER_HAS2     2
 
 /* This is only for PCI */
-#define UART_INFO_NUM  3
-struct mxpciuart_info {
+static const struct {
        int type;
        int tx_fifo;
        int rx_fifo;
@@ -190,51 +99,85 @@ struct mxpciuart_info {
        int rx_trigger;
        int rx_low_water;
        long max_baud;
-};
-
-static const struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = {
+} Gpci_uart_info[] = {
        {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
        {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
        {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
 };
+#define UART_INFO_NUM  ARRAY_SIZE(Gpci_uart_info)
 
+struct mxser_cardinfo {
+       char *name;
+       unsigned int nports;
+       unsigned int flags;
+};
 
-#ifdef CONFIG_PCI
+static const struct mxser_cardinfo mxser_cards[] = {
+/* 0*/ { "C168 series",        8, },
+       { "C104 series",        4, },
+       { "CI-104J series",     4, },
+       { "C168H/PCI series",   8, },
+       { "C104H/PCI series",   4, },
+/* 5*/ { "C102 series",        4, MXSER_HAS2 },        /* C102-ISA */
+       { "CI-132 series",      4, MXSER_HAS2 },
+       { "CI-134 series",      4, },
+       { "CP-132 series",      2, },
+       { "CP-114 series",      4, },
+/*10*/ { "CT-114 series",      4, },
+       { "CP-102 series",      2, MXSER_HIGHBAUD },
+       { "CP-104U series",     4, },
+       { "CP-168U series",     8, },
+       { "CP-132U series",     2, },
+/*15*/ { "CP-134U series",     4, },
+       { "CP-104JU series",    4, },
+       { "Moxa UC7000 Serial", 8, },           /* RC7000 */
+       { "CP-118U series",     8, },
+       { "CP-102UL series",    2, },
+/*20*/ { "CP-102U series",     2, },
+       { "CP-118EL series",    8, },
+       { "CP-168EL series",    8, },
+       { "CP-104EL series",    4, },
+       { "CB-108 series",      8, },
+/*25*/ { "CB-114 series",      4, },
+       { "CB-134I series",     4, },
+       { "CP-138U series",     8, },
+       { "POS-104UL series",   4, },
+       { "CP-114UL series",    4, }
+};
 
+/* driver_data correspond to the lines in the structure above
+   see also ISA probe function before you change something */
 static struct pci_device_id mxser_pcibrds[] = {
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C168_PCI},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C104_PCI},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP114},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CT114},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104U},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP168U},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132U},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP134U},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104JU},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_RC7000},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP118U},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102UL},
-       {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102U},
-       {0}
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168),   .driver_data = 3 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104),   .driver_data = 4 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132),  .driver_data = 8 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114),  .driver_data = 9 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114),  .driver_data = 10 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102),  .driver_data = 11 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108),       .driver_data = 24 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114),       .driver_data = 25 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I),      .driver_data = 26 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U),      .driver_data = 27 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL),    .driver_data = 28 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL),     .driver_data = 29 },
+       { }
 };
-
 MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
 
-
-#endif
-
-typedef struct _moxa_pci_info {
-       unsigned short busNum;
-       unsigned short devNum;
-       struct pci_dev *pdev;   /* add by Victor Yu. 06-23-2003 */
-} moxa_pci_info;
-
 static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
 static int ttymajor = MXSERMAJOR;
-static int calloutmajor = MXSERCUMAJOR;
-static int verbose = 0;
 
 /* Variables for insmod */
 
@@ -242,8 +185,6 @@ MODULE_AUTHOR("Casper Yang");
 MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
 module_param_array(ioaddr, int, NULL, 0);
 module_param(ttymajor, int, 0);
-module_param(calloutmajor, int, 0);
-module_param(verbose, bool, 0);
 MODULE_LICENSE("GPL");
 
 struct mxser_log {
@@ -278,67 +219,69 @@ struct mxser_mon_ext {
        int iftype[32];
 };
 
-struct mxser_hwconf {
-       int board_type;
-       int ports;
-       int irq;
-       int vector;
-       int vector_mask;
-       int uart_type;
-       int ioaddr[MXSER_PORTS_PER_BOARD];
-       int baud_base[MXSER_PORTS_PER_BOARD];
-       moxa_pci_info pciInfo;
-       int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
-       int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD];   /* add by Victor Yu. 09-04-2002 */
-       int opmode_ioaddr[MXSER_PORTS_PER_BOARD];       /* add by Victor Yu. 01-05-2004 */
-};
+struct mxser_board;
+
+struct mxser_port {
+       struct mxser_board *board;
+       struct tty_struct *tty;
+
+       unsigned long ioaddr;
+       unsigned long opmode_ioaddr;
+       int max_baud;
 
-struct mxser_struct {
-       int port;
-       int base;               /* port base address */
-       int irq;                /* port using irq no. */
-       int vector;             /* port irq vector */
-       int vectormask;         /* port vector mask */
        int rx_high_water;
        int rx_trigger;         /* Rx fifo trigger level */
        int rx_low_water;
        int baud_base;          /* max. speed */
-       int flags;              /* defined in tty.h */
        int type;               /* UART type */
-       struct tty_struct *tty;
-       int read_status_mask;
-       int ignore_status_mask;
-       int xmit_fifo_size;
-       int custom_divisor;
+       int flags;              /* defined in tty.h */
+
        int x_char;             /* xon/xoff character */
-       int close_delay;
-       unsigned short closing_wait;
        int IER;                /* Interrupt Enable Register */
        int MCR;                /* Modem control register */
+
+       unsigned char stop_rx;
+       unsigned char ldisc_stop_rx;
+
+       int custom_divisor;
+       int close_delay;
+       unsigned short closing_wait;
+       unsigned char err_shadow;
        unsigned long event;
+
        int count;              /* # of fd on device */
        int blocked_open;       /* # of blocked opens */
+       struct async_icount icount; /* kernel counters for 4 input interrupts */
+       int timeout;
+
+       int read_status_mask;
+       int ignore_status_mask;
+       int xmit_fifo_size;
        unsigned char *xmit_buf;
        int xmit_head;
        int xmit_tail;
        int xmit_cnt;
-       struct work_struct tqueue;
+
        struct ktermios normal_termios;
-       struct ktermios callout_termios;
-       wait_queue_head_t open_wait;
-       wait_queue_head_t close_wait;
-       wait_queue_head_t delta_msr_wait;
-       struct async_icount icount;     /* kernel counters for the 4 input interrupts */
-       int timeout;
-       int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
-       int MaxCanSetBaudRate;  /* add by Victor Yu. 09-04-2002 */
-       int opmode_ioaddr;      /* add by Victor Yu. 01-05-2004 */
-       unsigned char stop_rx;
-       unsigned char ldisc_stop_rx;
-       long realbaud;
+
        struct mxser_mon mon_data;
-       unsigned char err_shadow;
+
        spinlock_t slock;
+       wait_queue_head_t open_wait;
+       wait_queue_head_t delta_msr_wait;
+};
+
+struct mxser_board {
+       unsigned int idx;
+       int irq;
+       const struct mxser_cardinfo *info;
+       unsigned long vector;
+       unsigned long vector_mask;
+
+       int chip_flag;
+       int uart_type;
+
+       struct mxser_port ports[MXSER_PORTS_PER_BOARD];
 };
 
 struct mxser_mstatus {
@@ -356,73 +299,16 @@ static int mxserBoardCAP[MXSER_BOARDS] = {
        /*  0x180, 0x280, 0x200, 0x320 */
 };
 
+static struct mxser_board mxser_boards[MXSER_BOARDS];
 static struct tty_driver *mxvar_sdriver;
-static struct mxser_struct mxvar_table[MXSER_PORTS];
-static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
-static struct ktermios *mxvar_termios[MXSER_PORTS + 1];
-static struct ktermios *mxvar_termios_locked[MXSER_PORTS + 1];
 static struct mxser_log mxvar_log;
 static int mxvar_diagflag;
 static unsigned char mxser_msr[MXSER_PORTS + 1];
 static struct mxser_mon_ext mon_data_ext;
 static int mxser_set_baud_method[MXSER_PORTS + 1];
-static spinlock_t gm_lock;
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-
-static struct mxser_hwconf mxsercfg[MXSER_BOARDS];
-
-/*
- * static functions:
- */
-
-static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
-static int mxser_init(void);
-
-/* static void   mxser_poll(unsigned long); */
-static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
-static void mxser_do_softint(struct work_struct *);
-static int mxser_open(struct tty_struct *, struct file *);
-static void mxser_close(struct tty_struct *, struct file *);
-static int mxser_write(struct tty_struct *, const unsigned char *, int);
-static int mxser_write_room(struct tty_struct *);
-static void mxser_flush_buffer(struct tty_struct *);
-static int mxser_chars_in_buffer(struct tty_struct *);
-static void mxser_flush_chars(struct tty_struct *);
-static void mxser_put_char(struct tty_struct *, unsigned char);
-static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong);
-static int mxser_ioctl_special(unsigned int, void __user *);
-static void mxser_throttle(struct tty_struct *);
-static void mxser_unthrottle(struct tty_struct *);
-static void mxser_set_termios(struct tty_struct *, struct ktermios *);
-static void mxser_stop(struct tty_struct *);
-static void mxser_start(struct tty_struct *);
-static void mxser_hangup(struct tty_struct *);
-static void mxser_rs_break(struct tty_struct *, int);
-static irqreturn_t mxser_interrupt(int, void *);
-static void mxser_receive_chars(struct mxser_struct *, int *);
-static void mxser_transmit_chars(struct mxser_struct *);
-static void mxser_check_modem_status(struct mxser_struct *, int);
-static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
-static int mxser_startup(struct mxser_struct *);
-static void mxser_shutdown(struct mxser_struct *);
-static int mxser_change_speed(struct mxser_struct *, struct ktermios *old_termios);
-static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *);
-static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *);
-static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *);
-static void mxser_send_break(struct mxser_struct *, int);
-static int mxser_tiocmget(struct tty_struct *, struct file *);
-static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);
-static int mxser_set_baud(struct mxser_struct *info, long newspd);
-static void mxser_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static void mxser_startrx(struct tty_struct *tty);
-static void mxser_stoprx(struct tty_struct *tty);
 
 #ifdef CONFIG_PCI
-static int CheckIsMoxaMust(int io)
+static int __devinit CheckIsMoxaMust(unsigned long io)
 {
        u8 oldmcr, hwid;
        int i;
@@ -438,90 +324,15 @@ static int CheckIsMoxaMust(int io)
        }
 
        GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
-       for (i = 0; i < UART_TYPE_NUM; i++) {
-               if (hwid == Gmoxa_uart_id[i])
+       for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
+               if (hwid == Gpci_uart_info[i].type)
                        return (int)hwid;
        }
        return MOXA_OTHER_UART;
 }
 #endif
 
-/* above is modified by Victor Yu. 08-15-2002 */
-
-static const struct tty_operations mxser_ops = {
-       .open = mxser_open,
-       .close = mxser_close,
-       .write = mxser_write,
-       .put_char = mxser_put_char,
-       .flush_chars = mxser_flush_chars,
-       .write_room = mxser_write_room,
-       .chars_in_buffer = mxser_chars_in_buffer,
-       .flush_buffer = mxser_flush_buffer,
-       .ioctl = mxser_ioctl,
-       .throttle = mxser_throttle,
-       .unthrottle = mxser_unthrottle,
-       .set_termios = mxser_set_termios,
-       .stop = mxser_stop,
-       .start = mxser_start,
-       .hangup = mxser_hangup,
-       .break_ctl = mxser_rs_break,
-       .wait_until_sent = mxser_wait_until_sent,
-       .tiocmget = mxser_tiocmget,
-       .tiocmset = mxser_tiocmset,
-};
-
-/*
- * The MOXA Smartio/Industio serial driver boot-time initialization code!
- */
-
-static int __init mxser_module_init(void)
-{
-       int ret;
-
-       if (verbose)
-               printk(KERN_DEBUG "Loading module mxser ...\n");
-       ret = mxser_init();
-       if (verbose)
-               printk(KERN_DEBUG "Done.\n");
-       return ret;
-}
-
-static void __exit mxser_module_exit(void)
-{
-       int i, err;
-
-       if (verbose)
-               printk(KERN_DEBUG "Unloading module mxser ...\n");
-
-       err = tty_unregister_driver(mxvar_sdriver);
-       if (!err)
-               put_tty_driver(mxvar_sdriver);
-       else
-               printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n");
-
-       for (i = 0; i < MXSER_BOARDS; i++) {
-               struct pci_dev *pdev;
-
-               if (mxsercfg[i].board_type == -1)
-                       continue;
-               else {
-                       pdev = mxsercfg[i].pciInfo.pdev;
-                       free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
-                       if (pdev != NULL) {     /* PCI */
-                               release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
-                               release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
-                               pci_dev_put(pdev);
-                       } else {
-                               release_region(mxsercfg[i].ioaddr[0], 8 * mxsercfg[i].ports);
-                               release_region(mxsercfg[i].vector, 1);
-                       }
-               }
-       }
-       if (verbose)
-               printk(KERN_DEBUG "Done.\n");
-}
-
-static void process_txrx_fifo(struct mxser_struct *info)
+static void process_txrx_fifo(struct mxser_port *info)
 {
        int i;
 
@@ -530,476 +341,586 @@ static void process_txrx_fifo(struct mxser_struct *info)
                info->rx_high_water = 1;
                info->rx_low_water = 1;
                info->xmit_fifo_size = 1;
-       } else {
-               for (i = 0; i < UART_INFO_NUM; i++) {
-                       if (info->IsMoxaMustChipFlag == Gpci_uart_info[i].type) {
+       } else
+               for (i = 0; i < UART_INFO_NUM; i++)
+                       if (info->board->chip_flag == Gpci_uart_info[i].type) {
                                info->rx_trigger = Gpci_uart_info[i].rx_trigger;
                                info->rx_low_water = Gpci_uart_info[i].rx_low_water;
                                info->rx_high_water = Gpci_uart_info[i].rx_high_water;
                                info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size;
                                break;
                        }
-               }
-       }
 }
 
-static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
+static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
 {
-       struct mxser_struct *info;
-       int retval;
-       int i, n;
+       unsigned char status = 0;
 
-       n = board * MXSER_PORTS_PER_BOARD;
-       info = &mxvar_table[n];
-       /*if (verbose) */  {
-               printk(KERN_DEBUG "        ttyMI%d - ttyMI%d ",
-                       n, n + hwconf->ports - 1);
-               printk(" max. baud rate = %d bps.\n",
-                       hwconf->MaxCanSetBaudRate[0]);
-       }
-
-       for (i = 0; i < hwconf->ports; i++, n++, info++) {
-               info->port = n;
-               info->base = hwconf->ioaddr[i];
-               info->irq = hwconf->irq;
-               info->vector = hwconf->vector;
-               info->vectormask = hwconf->vector_mask;
-               info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; /* add by Victor Yu. 01-05-2004 */
-               info->stop_rx = 0;
-               info->ldisc_stop_rx = 0;
+       status = inb(baseaddr + UART_MSR);
 
-               info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag;
-               /* Enhance mode enabled here */
-               if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
-                       ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base);
-               }
+       mxser_msr[port] &= 0x0F;
+       mxser_msr[port] |= status;
+       status = mxser_msr[port];
+       if (mode)
+               mxser_msr[port] = 0;
 
-               info->flags = ASYNC_SHARE_IRQ;
-               info->type = hwconf->uart_type;
-               info->baud_base = hwconf->baud_base[i];
+       return status;
+}
 
-               info->MaxCanSetBaudRate = hwconf->MaxCanSetBaudRate[i];
+static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
+               struct mxser_port *port)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int retval;
+       int do_clocal = 0;
+       unsigned long flags;
 
-               process_txrx_fifo(info);
+       /*
+        * If non-blocking mode is set, or the port is not enabled,
+        * then make the check up front and then exit.
+        */
+       if ((filp->f_flags & O_NONBLOCK) ||
+                       test_bit(TTY_IO_ERROR, &tty->flags)) {
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
 
+       if (tty->termios->c_cflag & CLOCAL)
+               do_clocal = 1;
 
-               info->custom_divisor = hwconf->baud_base[i] * 16;
-               info->close_delay = 5 * HZ / 10;
-               info->closing_wait = 30 * HZ;
-               INIT_WORK(&info->tqueue, mxser_do_softint);
-               info->normal_termios = mxvar_sdriver->init_termios;
-               init_waitqueue_head(&info->open_wait);
-               init_waitqueue_head(&info->close_wait);
-               init_waitqueue_head(&info->delta_msr_wait);
-               memset(&info->mon_data, 0, sizeof(struct mxser_mon));
-               info->err_shadow = 0;
-               spin_lock_init(&info->slock);
-       }
        /*
-        * Allocate the IRQ if necessary
+        * Block waiting for the carrier detect and the line to become
+        * free (i.e., not in use by the callout).  While we are in
+        * this loop, port->count is dropped by one, so that
+        * mxser_close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
         */
+       retval = 0;
+       add_wait_queue(&port->open_wait, &wait);
 
-
-       /* before set INT ISR, disable all int */
-       for (i = 0; i < hwconf->ports; i++) {
-               outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0,
-                       hwconf->ioaddr[i] + UART_IER);
+       spin_lock_irqsave(&port->slock, flags);
+       if (!tty_hung_up_p(filp))
+               port->count--;
+       spin_unlock_irqrestore(&port->slock, flags);
+       port->blocked_open++;
+       while (1) {
+               spin_lock_irqsave(&port->slock, flags);
+               outb(inb(port->ioaddr + UART_MCR) |
+                       UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
+               spin_unlock_irqrestore(&port->slock, flags);
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+                       if (port->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;
+                       break;
+               }
+               if (!(port->flags & ASYNC_CLOSING) &&
+                               (do_clocal ||
+                               (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               schedule();
        }
-
-       n = board * MXSER_PORTS_PER_BOARD;
-       info = &mxvar_table[n];
-
-       retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),
-                               "mxser", info);
-       if (retval) {
-               printk(KERN_ERR "Board %d: %s",
-                       board, mxser_brdname[hwconf->board_type - 1]);
-               printk("  Request irq failed, IRQ (%d) may conflict with"
-                       " another device.\n", info->irq);
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&port->open_wait, &wait);
+       if (!tty_hung_up_p(filp))
+               port->count++;
+       port->blocked_open--;
+       if (retval)
                return retval;
-       }
+       port->flags |= ASYNC_NORMAL_ACTIVE;
        return 0;
 }
 
-static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
+static int mxser_set_baud(struct mxser_port *info, long newspd)
 {
-       mxsercfg[board] = *hwconf;
-}
+       int quot = 0, baud;
+       unsigned char cval;
 
-#ifdef CONFIG_PCI
-static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf)
-{
-       int i, j;
-       /* unsigned int val; */
-       unsigned int ioaddress;
-       struct pci_dev *pdev = hwconf->pciInfo.pdev;
+       if (!info->tty || !info->tty->termios)
+               return -1;
 
-       /* io address */
-       hwconf->board_type = board_type;
-       hwconf->ports = mxser_numports[board_type - 1];
-       ioaddress = pci_resource_start(pdev, 2);
-       request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2),
-                       "mxser(IO)");
+       if (!(info->ioaddr))
+               return -1;
 
-       for (i = 0; i < hwconf->ports; i++)
-               hwconf->ioaddr[i] = ioaddress + 8 * i;
+       if (newspd > info->max_baud)
+               return -1;
 
-       /* vector */
-       ioaddress = pci_resource_start(pdev, 3);
-       request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3),
-                       "mxser(vector)");
-       hwconf->vector = ioaddress;
+       if (newspd == 134) {
+               quot = 2 * info->baud_base / 269;
+               tty_encode_baud_rate(info->tty, 134, 134);
+       } else if (newspd) {
+               quot = info->baud_base / newspd;
+               if (quot == 0)
+                       quot = 1;
+               baud = info->baud_base/quot;
+               tty_encode_baud_rate(info->tty, baud, baud);
+       } else {
+               quot = 0;
+       }
 
-       /* irq */
-       hwconf->irq = hwconf->pciInfo.pdev->irq;
+       info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
+       info->timeout += HZ / 50;       /* Add .02 seconds of slop */
+
+       if (quot) {
+               info->MCR |= UART_MCR_DTR;
+               outb(info->MCR, info->ioaddr + UART_MCR);
+       } else {
+               info->MCR &= ~UART_MCR_DTR;
+               outb(info->MCR, info->ioaddr + UART_MCR);
+               return 0;
+       }
 
-       hwconf->IsMoxaMustChipFlag = CheckIsMoxaMust(hwconf->ioaddr[0]);
-       hwconf->uart_type = PORT_16550A;
-       hwconf->vector_mask = 0;
+       cval = inb(info->ioaddr + UART_LCR);
 
+       outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR);    /* set DLAB */
 
-       for (i = 0; i < hwconf->ports; i++) {
-               for (j = 0; j < UART_INFO_NUM; j++) {
-                       if (Gpci_uart_info[j].type == hwconf->IsMoxaMustChipFlag) {
-                               hwconf->MaxCanSetBaudRate[i] = Gpci_uart_info[j].max_baud;
+       outb(quot & 0xff, info->ioaddr + UART_DLL);     /* LS of divisor */
+       outb(quot >> 8, info->ioaddr + UART_DLM);       /* MS of divisor */
+       outb(cval, info->ioaddr + UART_LCR);    /* reset DLAB */
 
-                               /* exception....CP-102 */
-                               if (board_type == MXSER_BOARD_CP102)
-                                       hwconf->MaxCanSetBaudRate[i] = 921600;
-                               break;
-                       }
-               }
-       }
+#ifdef BOTHER
+       if (C_BAUD(info->tty) == BOTHER) {
+               quot = info->baud_base % newspd;
+               quot *= 8;
+               if (quot % newspd > newspd / 2) {
+                       quot /= newspd;
+                       quot++;
+               } else
+                       quot /= newspd;
 
-       if (hwconf->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID) {
-               for (i = 0; i < hwconf->ports; i++) {
-                       if (i < 4)
-                               hwconf->opmode_ioaddr[i] = ioaddress + 4;
-                       else
-                               hwconf->opmode_ioaddr[i] = ioaddress + 0x0c;
-               }
-               outb(0, ioaddress + 4); /* default set to RS232 mode */
-               outb(0, ioaddress + 0x0c);      /* default set to RS232 mode */
-       }
+               SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot);
+       } else
+#endif
+               SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0);
 
-       for (i = 0; i < hwconf->ports; i++) {
-               hwconf->vector_mask |= (1 << i);
-               hwconf->baud_base[i] = 921600;
-       }
        return 0;
 }
-#endif
 
-static int mxser_init(void)
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static int mxser_change_speed(struct mxser_port *info,
+               struct ktermios *old_termios)
 {
-       int i, m, retval, b, n;
-       struct pci_dev *pdev = NULL;
-       int index;
-       unsigned char busnum, devnum;
-       struct mxser_hwconf hwconf;
+       unsigned cflag, cval, fcr;
+       int ret = 0;
+       unsigned char status;
 
-       mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
-       if (!mxvar_sdriver)
-               return -ENOMEM;
-       spin_lock_init(&gm_lock);
-
-       for (i = 0; i < MXSER_BOARDS; i++) {
-               mxsercfg[i].board_type = -1;
-       }
-
-       printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
-               MXSER_VERSION);
-
-       /* Initialize the tty_driver structure */
-       memset(mxvar_sdriver, 0, sizeof(struct tty_driver));
-       mxvar_sdriver->owner = THIS_MODULE;
-       mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
-       mxvar_sdriver->name = "ttyMI";
-       mxvar_sdriver->major = ttymajor;
-       mxvar_sdriver->minor_start = 0;
-       mxvar_sdriver->num = MXSER_PORTS + 1;
-       mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
-       mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
-       mxvar_sdriver->init_termios = tty_std_termios;
-       mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
-       mxvar_sdriver->init_termios.c_ispeed = 9600;
-       mxvar_sdriver->init_termios.c_ospeed = 9600;
-       mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(mxvar_sdriver, &mxser_ops);
-       mxvar_sdriver->ttys = mxvar_tty;
-       mxvar_sdriver->termios = mxvar_termios;
-       mxvar_sdriver->termios_locked = mxvar_termios_locked;
+       if (!info->tty || !info->tty->termios)
+               return ret;
+       cflag = info->tty->termios->c_cflag;
+       if (!(info->ioaddr))
+               return ret;
 
-       mxvar_diagflag = 0;
-       memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct));
-       memset(&mxvar_log, 0, sizeof(struct mxser_log));
+       if (mxser_set_baud_method[info->tty->index] == 0)
+               mxser_set_baud(info, tty_get_baud_rate(info->tty));
 
-       memset(&mxser_msr, 0, sizeof(unsigned char) * (MXSER_PORTS + 1));
-       memset(&mon_data_ext, 0, sizeof(struct mxser_mon_ext));
-       memset(&mxser_set_baud_method, 0, sizeof(int) * (MXSER_PORTS + 1));
-       memset(&hwconf, 0, sizeof(struct mxser_hwconf));
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+       case CS5:
+               cval = 0x00;
+               break;
+       case CS6:
+               cval = 0x01;
+               break;
+       case CS7:
+               cval = 0x02;
+               break;
+       case CS8:
+               cval = 0x03;
+               break;
+       default:
+               cval = 0x00;
+               break;          /* too keep GCC shut... */
+       }
+       if (cflag & CSTOPB)
+               cval |= 0x04;
+       if (cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+       if (cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
 
-       m = 0;
-       /* Start finding ISA boards here */
-       for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
-               int cap;
-
-               if (!(cap = mxserBoardCAP[b]))
-                       continue;
-
-               retval = mxser_get_ISA_conf(cap, &hwconf);
-
-               if (retval != 0)
-                       printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
-                               mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
-
-               if (retval <= 0) {
-                       if (retval == MXSER_ERR_IRQ)
-                               printk(KERN_ERR "Invalid interrupt number, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                               printk(KERN_ERR "Invalid interrupt number, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_VECTOR)
-                               printk(KERN_ERR "Invalid interrupt vector, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_IOADDR)
-                               printk(KERN_ERR "Invalid I/O address, "
-                                       "board not configured\n");
-
-                       continue;
+       if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
+               if (info->board->chip_flag) {
+                       fcr = UART_FCR_ENABLE_FIFO;
+                       fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+                       SET_MOXA_MUST_FIFO_VALUE(info);
+               } else
+                       fcr = 0;
+       } else {
+               fcr = UART_FCR_ENABLE_FIFO;
+               if (info->board->chip_flag) {
+                       fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+                       SET_MOXA_MUST_FIFO_VALUE(info);
+               } else {
+                       switch (info->rx_trigger) {
+                       case 1:
+                               fcr |= UART_FCR_TRIGGER_1;
+                               break;
+                       case 4:
+                               fcr |= UART_FCR_TRIGGER_4;
+                               break;
+                       case 8:
+                               fcr |= UART_FCR_TRIGGER_8;
+                               break;
+                       default:
+                               fcr |= UART_FCR_TRIGGER_14;
+                               break;
+                       }
                }
-
-               hwconf.pciInfo.busNum = 0;
-               hwconf.pciInfo.devNum = 0;
-               hwconf.pciInfo.pdev = NULL;
-
-               mxser_getcfg(m, &hwconf);
-               /*
-                * init mxsercfg first,
-                * or mxsercfg data is not correct on ISR.
-                */
-               /* mxser_initbrd will hook ISR. */
-               if (mxser_initbrd(m, &hwconf) < 0)
-                       continue;
-
-               m++;
        }
 
-       /* Start finding ISA boards from module arg */
-       for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
-               int cap;
-
-               if (!(cap = ioaddr[b]))
-                       continue;
-
-               retval = mxser_get_ISA_conf(cap, &hwconf);
-
-               if (retval != 0)
-                       printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
-                               mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
-
-               if (retval <= 0) {
-                       if (retval == MXSER_ERR_IRQ)
-                               printk(KERN_ERR "Invalid interrupt number, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                               printk(KERN_ERR "Invalid interrupt number, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_VECTOR)
-                               printk(KERN_ERR "Invalid interrupt vector, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_IOADDR)
-                               printk(KERN_ERR "Invalid I/O address, "
-                                       "board not configured\n");
-
-                       continue;
+       /* CTS flow control flag and modem status interrupts */
+       info->IER &= ~UART_IER_MSI;
+       info->MCR &= ~UART_MCR_AFE;
+       if (cflag & CRTSCTS) {
+               info->flags |= ASYNC_CTS_FLOW;
+               info->IER |= UART_IER_MSI;
+               if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
+                       info->MCR |= UART_MCR_AFE;
+               } else {
+                       status = inb(info->ioaddr + UART_MSR);
+                       if (info->tty->hw_stopped) {
+                               if (status & UART_MSR_CTS) {
+                                       info->tty->hw_stopped = 0;
+                                       if (info->type != PORT_16550A &&
+                                                       !info->board->chip_flag) {
+                                               outb(info->IER & ~UART_IER_THRI,
+                                                       info->ioaddr +
+                                                       UART_IER);
+                                               info->IER |= UART_IER_THRI;
+                                               outb(info->IER, info->ioaddr +
+                                                               UART_IER);
+                                       }
+                                       tty_wakeup(info->tty);
+                               }
+                       } else {
+                               if (!(status & UART_MSR_CTS)) {
+                                       info->tty->hw_stopped = 1;
+                                       if ((info->type != PORT_16550A) &&
+                                                       (!info->board->chip_flag)) {
+                                               info->IER &= ~UART_IER_THRI;
+                                               outb(info->IER, info->ioaddr +
+                                                               UART_IER);
+                                       }
+                               }
+                       }
                }
+       } else {
+               info->flags &= ~ASYNC_CTS_FLOW;
+       }
+       outb(info->MCR, info->ioaddr + UART_MCR);
+       if (cflag & CLOCAL) {
+               info->flags &= ~ASYNC_CHECK_CD;
+       } else {
+               info->flags |= ASYNC_CHECK_CD;
+               info->IER |= UART_IER_MSI;
+       }
+       outb(info->IER, info->ioaddr + UART_IER);
+
+       /*
+        * Set up parity check flag
+        */
+       info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (I_INPCK(info->tty))
+               info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+               info->read_status_mask |= UART_LSR_BI;
 
-               hwconf.pciInfo.busNum = 0;
-               hwconf.pciInfo.devNum = 0;
-               hwconf.pciInfo.pdev = NULL;
+       info->ignore_status_mask = 0;
 
-               mxser_getcfg(m, &hwconf);
+       if (I_IGNBRK(info->tty)) {
+               info->ignore_status_mask |= UART_LSR_BI;
+               info->read_status_mask |= UART_LSR_BI;
                /*
-                * init mxsercfg first,
-                * or mxsercfg data is not correct on ISR.
+                * If we're ignore parity and break indicators, ignore
+                * overruns too.  (For real raw support).
                 */
-               /* mxser_initbrd will hook ISR. */
-               if (mxser_initbrd(m, &hwconf) < 0)
-                       continue;
-
-               m++;
+               if (I_IGNPAR(info->tty)) {
+                       info->ignore_status_mask |=
+                                               UART_LSR_OE |
+                                               UART_LSR_PE |
+                                               UART_LSR_FE;
+                       info->read_status_mask |=
+                                               UART_LSR_OE |
+                                               UART_LSR_PE |
+                                               UART_LSR_FE;
+               }
        }
-
-       /* start finding PCI board here */
-#ifdef CONFIG_PCI
-       n = ARRAY_SIZE(mxser_pcibrds) - 1;
-       index = 0;
-       b = 0;
-       while (b < n) {
-               pdev = pci_get_device(mxser_pcibrds[b].vendor,
-                               mxser_pcibrds[b].device, pdev);
-               if (pdev == NULL) {
-                       b++;
-                       continue;
+       if (info->board->chip_flag) {
+               SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
+               SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
+               if (I_IXON(info->tty)) {
+                       ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+               } else {
+                       DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
                }
-               hwconf.pciInfo.busNum = busnum = pdev->bus->number;
-               hwconf.pciInfo.devNum = devnum = PCI_SLOT(pdev->devfn) << 3;
-               hwconf.pciInfo.pdev = pdev;
-               printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
-                       mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1],
-                       busnum, devnum >> 3);
-               index++;
-               if (m >= MXSER_BOARDS)
-                       printk(KERN_ERR
-                               "Too many Smartio/Industio family boards find "
-                               "(maximum %d), board not configured\n",
-                               MXSER_BOARDS);
-               else {
-                       if (pci_enable_device(pdev)) {
-                               printk(KERN_ERR "Moxa SmartI/O PCI enable "
-                                       "fail !\n");
-                               continue;
-                       }
-                       retval = mxser_get_PCI_conf(busnum, devnum,
-                                       (int)mxser_pcibrds[b].driver_data,
-                                       &hwconf);
-                       if (retval < 0) {
-                               if (retval == MXSER_ERR_IRQ)
-                                       printk(KERN_ERR
-                                               "Invalid interrupt number, "
-                                               "board not configured\n");
-                               else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                                       printk(KERN_ERR
-                                               "Invalid interrupt number, "
-                                               "board not configured\n");
-                               else if (retval == MXSER_ERR_VECTOR)
-                                       printk(KERN_ERR
-                                               "Invalid interrupt vector, "
-                                               "board not configured\n");
-                               else if (retval == MXSER_ERR_IOADDR)
-                                       printk(KERN_ERR
-                                               "Invalid I/O address, "
-                                               "board not configured\n");
-                               continue;
-                       }
-                       mxser_getcfg(m, &hwconf);
-                       /* init mxsercfg first,
-                        * or mxsercfg data is not correct on ISR.
-                        */
-                       /* mxser_initbrd will hook ISR. */
-                       if (mxser_initbrd(m, &hwconf) < 0)
-                               continue;
-                       m++;
-                       /* Keep an extra reference if we succeeded. It will
-                          be returned at unload time */
-                       pci_dev_get(pdev);
+               if (I_IXOFF(info->tty)) {
+                       ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+               } else {
+                       DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
                }
        }
-#endif
 
-       retval = tty_register_driver(mxvar_sdriver);
-       if (retval) {
-               printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family"
-                               " driver !\n");
-               put_tty_driver(mxvar_sdriver);
 
-               for (i = 0; i < MXSER_BOARDS; i++) {
-                       if (mxsercfg[i].board_type == -1)
-                               continue;
-                       else {
-                               free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
-                               /* todo: release io, vector */
-                       }
-               }
-               return retval;
-       }
+       outb(fcr, info->ioaddr + UART_FCR);     /* set fcr */
+       outb(cval, info->ioaddr + UART_LCR);
 
-       return 0;
+       return ret;
 }
 
-static void mxser_do_softint(struct work_struct *work)
+static void mxser_check_modem_status(struct mxser_port *port, int status)
 {
-       struct mxser_struct *info =
-               container_of(work, struct mxser_struct, tqueue);
-       struct tty_struct *tty;
+       /* update input line counters */
+       if (status & UART_MSR_TERI)
+               port->icount.rng++;
+       if (status & UART_MSR_DDSR)
+               port->icount.dsr++;
+       if (status & UART_MSR_DDCD)
+               port->icount.dcd++;
+       if (status & UART_MSR_DCTS)
+               port->icount.cts++;
+       port->mon_data.modem_status = status;
+       wake_up_interruptible(&port->delta_msr_wait);
 
-       tty = info->tty;
+       if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+               if (status & UART_MSR_DCD)
+                       wake_up_interruptible(&port->open_wait);
+       }
 
-       if (tty) {
-               if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event))
-                       tty_wakeup(tty);
-               if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event))
-                       tty_hangup(tty);
+       if (port->flags & ASYNC_CTS_FLOW) {
+               if (port->tty->hw_stopped) {
+                       if (status & UART_MSR_CTS) {
+                               port->tty->hw_stopped = 0;
+
+                               if ((port->type != PORT_16550A) &&
+                                               (!port->board->chip_flag)) {
+                                       outb(port->IER & ~UART_IER_THRI,
+                                               port->ioaddr + UART_IER);
+                                       port->IER |= UART_IER_THRI;
+                                       outb(port->IER, port->ioaddr +
+                                                       UART_IER);
+                               }
+                               tty_wakeup(port->tty);
+                       }
+               } else {
+                       if (!(status & UART_MSR_CTS)) {
+                               port->tty->hw_stopped = 1;
+                               if (port->type != PORT_16550A &&
+                                               !port->board->chip_flag) {
+                                       port->IER &= ~UART_IER_THRI;
+                                       outb(port->IER, port->ioaddr +
+                                                       UART_IER);
+                               }
+                       }
+               }
        }
 }
 
-static unsigned char mxser_get_msr(int baseaddr, int mode, int port, struct mxser_struct *info)
+static int mxser_startup(struct mxser_port *info)
 {
-       unsigned char status = 0;
-
-       status = inb(baseaddr + UART_MSR);
-
-       mxser_msr[port] &= 0x0F;
-       mxser_msr[port] |= status;
-       status = mxser_msr[port];
-       if (mode)
-               mxser_msr[port] = 0;
+       unsigned long page;
+       unsigned long flags;
 
-       return status;
-}
+       page = __get_free_page(GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
 
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int mxser_open(struct tty_struct *tty, struct file *filp)
-{
-       struct mxser_struct *info;
-       int retval, line;
+       spin_lock_irqsave(&info->slock, flags);
 
-       /* initialize driver_data in case something fails */
-       tty->driver_data = NULL;
+       if (info->flags & ASYNC_INITIALIZED) {
+               free_page(page);
+               spin_unlock_irqrestore(&info->slock, flags);
+               return 0;
+       }
 
-       line = tty->index;
-       if (line == MXSER_PORTS)
+       if (!info->ioaddr || !info->type) {
+               if (info->tty)
+                       set_bit(TTY_IO_ERROR, &info->tty->flags);
+               free_page(page);
+               spin_unlock_irqrestore(&info->slock, flags);
                return 0;
-       if (line < 0 || line > MXSER_PORTS)
-               return -ENODEV;
-       info = mxvar_table + line;
-       if (!info->base)
-               return -ENODEV;
+       }
+       if (info->xmit_buf)
+               free_page(page);
+       else
+               info->xmit_buf = (unsigned char *) page;
 
-       tty->driver_data = info;
-       info->tty = tty;
        /*
-        * Start up serial port
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in mxser_change_speed())
         */
-       retval = mxser_startup(info);
-       if (retval)
-               return retval;
-
-       retval = mxser_block_til_ready(tty, filp, info);
-       if (retval)
-               return retval;
-
-       info->count++;
+       if (info->board->chip_flag)
+               outb((UART_FCR_CLEAR_RCVR |
+                       UART_FCR_CLEAR_XMIT |
+                       MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR);
+       else
+               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+                       info->ioaddr + UART_FCR);
 
-       if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-               if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-                       *tty->termios = info->normal_termios;
-               else
-                       *tty->termios = info->callout_termios;
-               mxser_change_speed(info, NULL);
-       }
+       /*
+        * At this point there's no way the LSR could still be 0xFF;
+        * if it is, then bail out, because there's likely no UART
+        * here.
+        */
+       if (inb(info->ioaddr + UART_LSR) == 0xff) {
+               spin_unlock_irqrestore(&info->slock, flags);
+               if (capable(CAP_SYS_ADMIN)) {
+                       if (info->tty)
+                               set_bit(TTY_IO_ERROR, &info->tty->flags);
+                       return 0;
+               } else
+                       return -ENODEV;
+       }
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) inb(info->ioaddr + UART_LSR);
+       (void) inb(info->ioaddr + UART_RX);
+       (void) inb(info->ioaddr + UART_IIR);
+       (void) inb(info->ioaddr + UART_MSR);
+
+       /*
+        * Now, initialize the UART
+        */
+       outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR);  /* reset DLAB */
+       info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+       outb(info->MCR, info->ioaddr + UART_MCR);
+
+       /*
+        * Finally, enable interrupts
+        */
+       info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+
+       if (info->board->chip_flag)
+               info->IER |= MOXA_MUST_IER_EGDAI;
+       outb(info->IER, info->ioaddr + UART_IER);       /* enable interrupts */
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       (void) inb(info->ioaddr + UART_LSR);
+       (void) inb(info->ioaddr + UART_RX);
+       (void) inb(info->ioaddr + UART_IIR);
+       (void) inb(info->ioaddr + UART_MSR);
+
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+       /*
+        * and set the speed of the serial port
+        */
+       mxser_change_speed(info, NULL);
+       info->flags |= ASYNC_INITIALIZED;
+       spin_unlock_irqrestore(&info->slock, flags);
+
+       return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts maybe disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void mxser_shutdown(struct mxser_port *info)
+{
+       unsigned long flags;
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+       spin_lock_irqsave(&info->slock, flags);
+
+       /*
+        * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+        * here so the queue might never be waken up
+        */
+       wake_up_interruptible(&info->delta_msr_wait);
+
+       /*
+        * Free the IRQ, if necessary
+        */
+       if (info->xmit_buf) {
+               free_page((unsigned long) info->xmit_buf);
+               info->xmit_buf = NULL;
+       }
+
+       info->IER = 0;
+       outb(0x00, info->ioaddr + UART_IER);
+
+       if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+               info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
+       outb(info->MCR, info->ioaddr + UART_MCR);
+
+       /* clear Rx/Tx FIFO's */
+       if (info->board->chip_flag)
+               outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
+                               MOXA_MUST_FCR_GDA_MODE_ENABLE,
+                               info->ioaddr + UART_FCR);
+       else
+               outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+                       info->ioaddr + UART_FCR);
+
+       /* read data port to reset things */
+       (void) inb(info->ioaddr + UART_RX);
+
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       info->flags &= ~ASYNC_INITIALIZED;
+
+       if (info->board->chip_flag)
+               SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+
+       spin_unlock_irqrestore(&info->slock, flags);
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int mxser_open(struct tty_struct *tty, struct file *filp)
+{
+       struct mxser_port *info;
+       unsigned long flags;
+       int retval, line;
+
+       line = tty->index;
+       if (line == MXSER_PORTS)
+               return 0;
+       if (line < 0 || line > MXSER_PORTS)
+               return -ENODEV;
+       info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
+       if (!info->ioaddr)
+               return -ENODEV;
 
+       tty->driver_data = info;
+       info->tty = tty;
        /*
-       status = mxser_get_msr(info->base, 0, info->port);
-       mxser_check_modem_status(info, status);
-       */
+        * Start up serial port
+        */
+       spin_lock_irqsave(&info->slock, flags);
+       info->count++;
+       spin_unlock_irqrestore(&info->slock, flags);
+       retval = mxser_startup(info);
+       if (retval)
+               return retval;
+
+       retval = mxser_block_til_ready(tty, filp, info);
+       if (retval)
+               return retval;
 
        /* unmark here for very high baud rate (ex. 921600 bps) used */
        tty->low_latency = 1;
@@ -1014,11 +935,10 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
  */
 static void mxser_close(struct tty_struct *tty, struct file *filp)
 {
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
 
        unsigned long timeout;
        unsigned long flags;
-       struct tty_ldisc *ld;
 
        if (tty->index == MXSER_PORTS)
                return;
@@ -1045,7 +965,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
        }
        if (--info->count < 0) {
                printk(KERN_ERR "mxser_close: bad serial port count for "
-                       "ttys%d: %d\n", info->port, info->count);
+                       "ttys%d: %d\n", tty->index, info->count);
                info->count = 0;
        }
        if (info->count) {
@@ -1074,20 +994,18 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
         * line status register.
         */
        info->IER &= ~UART_IER_RLSI;
-       if (info->IsMoxaMustChipFlag)
+       if (info->board->chip_flag)
                info->IER &= ~MOXA_MUST_RECV_ISR;
-/* by William
-       info->read_status_mask &= ~UART_LSR_DR;
-*/
+
        if (info->flags & ASYNC_INITIALIZED) {
-               outb(info->IER, info->base + UART_IER);
+               outb(info->IER, info->ioaddr + UART_IER);
                /*
                 * Before we drop DTR, make sure the UART transmitter
                 * has completely drained; this is especially
                 * important if there is a transmit FIFO!
                 */
                timeout = jiffies + HZ;
-               while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) {
+               while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
                        schedule_timeout_interruptible(5);
                        if (time_after(jiffies, timeout))
                                break;
@@ -1097,14 +1015,9 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
 
        if (tty->driver->flush_buffer)
                tty->driver->flush_buffer(tty);
-               
-       ld = tty_ldisc_ref(tty);
-       if (ld) {
-               if (ld->flush_buffer)
-                       ld->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-               
+
+       tty_ldisc_flush(tty);
+
        tty->closing = 0;
        info->event = 0;
        info->tty = NULL;
@@ -1115,14 +1028,12 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
        }
 
        info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-
 }
 
 static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        int c, total = 0;
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
        if (!info->xmit_buf)
@@ -1146,13 +1057,15 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
                total += c;
        }
 
-       if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
+       if (info->xmit_cnt && !tty->stopped) {
                if (!tty->hw_stopped ||
                                (info->type == PORT_16550A) ||
-                               (info->IsMoxaMustChipFlag)) {
+                               (info->board->chip_flag)) {
                        spin_lock_irqsave(&info->slock, flags);
+                       outb(info->IER & ~UART_IER_THRI, info->ioaddr +
+                                       UART_IER);
                        info->IER |= UART_IER_THRI;
-                       outb(info->IER, info->base + UART_IER);
+                       outb(info->IER, info->ioaddr + UART_IER);
                        spin_unlock_irqrestore(&info->slock, flags);
                }
        }
@@ -1161,7 +1074,7 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
 
 static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
        if (!info->xmit_buf)
@@ -1175,13 +1088,14 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
        info->xmit_head &= SERIAL_XMIT_SIZE - 1;
        info->xmit_cnt++;
        spin_unlock_irqrestore(&info->slock, flags);
-       if (!tty->stopped && !(info->IER & UART_IER_THRI)) {
+       if (!tty->stopped) {
                if (!tty->hw_stopped ||
                                (info->type == PORT_16550A) ||
-                               info->IsMoxaMustChipFlag) {
+                               info->board->chip_flag) {
                        spin_lock_irqsave(&info->slock, flags);
+                       outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
                        info->IER |= UART_IER_THRI;
-                       outb(info->IER, info->base + UART_IER);
+                       outb(info->IER, info->ioaddr + UART_IER);
                        spin_unlock_irqrestore(&info->slock, flags);
                }
        }
@@ -1190,7 +1104,7 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
 
 static void mxser_flush_chars(struct tty_struct *tty)
 {
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
        if (info->xmit_cnt <= 0 ||
@@ -1198,21 +1112,22 @@ static void mxser_flush_chars(struct tty_struct *tty)
                        !info->xmit_buf ||
                        (tty->hw_stopped &&
                         (info->type != PORT_16550A) &&
-                        (!info->IsMoxaMustChipFlag)
+                        (!info->board->chip_flag)
                        ))
                return;
 
        spin_lock_irqsave(&info->slock, flags);
 
+       outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
        info->IER |= UART_IER_THRI;
-       outb(info->IER, info->base + UART_IER);
+       outb(info->IER, info->ioaddr + UART_IER);
 
        spin_unlock_irqrestore(&info->slock, flags);
 }
 
 static int mxser_write_room(struct tty_struct *tty)
 {
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
        int ret;
 
        ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
@@ -1223,13 +1138,13 @@ static int mxser_write_room(struct tty_struct *tty)
 
 static int mxser_chars_in_buffer(struct tty_struct *tty)
 {
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
        return info->xmit_cnt;
 }
 
 static void mxser_flush_buffer(struct tty_struct *tty)
 {
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
        char fcr;
        unsigned long flags;
 
@@ -1237,360 +1152,421 @@ static void mxser_flush_buffer(struct tty_struct *tty)
        spin_lock_irqsave(&info->slock, flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
-       /* below added by shinhay */
-       fcr = inb(info->base + UART_FCR);
+       fcr = inb(info->ioaddr + UART_FCR);
        outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
-               info->base + UART_FCR);
-       outb(fcr, info->base + UART_FCR);
+               info->ioaddr + UART_FCR);
+       outb(fcr, info->ioaddr + UART_FCR);
 
        spin_unlock_irqrestore(&info->slock, flags);
-       /* above added by shinhay */
 
        tty_wakeup(tty);
 }
 
-static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+/*
+ * ------------------------------------------------------------
+ * friends of mxser_ioctl()
+ * ------------------------------------------------------------
+ */
+static int mxser_get_serial_info(struct mxser_port *info,
+               struct serial_struct __user *retinfo)
 {
-       struct mxser_struct *info = tty->driver_data;
-       int retval;
-       struct async_icount cprev, cnow;        /* kernel counter temps */
-       struct serial_icounter_struct __user *p_cuser;
-       unsigned long templ;
-       unsigned long flags;
-       void __user *argp = (void __user *)arg;
+       struct serial_struct tmp = {
+               .type = info->type,
+               .line = info->tty->index,
+               .port = info->ioaddr,
+               .irq = info->board->irq,
+               .flags = info->flags,
+               .baud_base = info->baud_base,
+               .close_delay = info->close_delay,
+               .closing_wait = info->closing_wait,
+               .custom_divisor = info->custom_divisor,
+               .hub6 = 0
+       };
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
 
-       if (tty->index == MXSER_PORTS)
-               return mxser_ioctl_special(cmd, argp);
+static int mxser_set_serial_info(struct mxser_port *info,
+               struct serial_struct __user *new_info)
+{
+       struct serial_struct new_serial;
+       speed_t baud;
+       unsigned long sl_flags;
+       unsigned int flags;
+       int retval = 0;
 
-       /* following add by Victor Yu. 01-05-2004 */
-       if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
-               int opmode, p;
-               static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
-               int shiftbit;
-               unsigned char val, mask;
+       if (!new_info || !info->ioaddr)
+               return -ENODEV;
+       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+               return -EFAULT;
 
-               p = info->port % 4;
-               if (cmd == MOXA_SET_OP_MODE) {
-                       if (get_user(opmode, (int __user *) argp))
-                               return -EFAULT;
-                       if (opmode != RS232_MODE &&
-                                       opmode != RS485_2WIRE_MODE &&
-                                       opmode != RS422_MODE &&
-                                       opmode != RS485_4WIRE_MODE)
-                               return -EFAULT;
-                       mask = ModeMask[p];
-                       shiftbit = p * 2;
-                       val = inb(info->opmode_ioaddr);
-                       val &= mask;
-                       val |= (opmode << shiftbit);
-                       outb(val, info->opmode_ioaddr);
-               } else {
-                       shiftbit = p * 2;
-                       opmode = inb(info->opmode_ioaddr) >> shiftbit;
-                       opmode &= OP_MODE_MASK;
-                       if (copy_to_user(argp, &opmode, sizeof(int)))
-                               return -EFAULT;
-               }
-               return 0;
-       }
-       /* above add by Victor Yu. 01-05-2004 */
+       if (new_serial.irq != info->board->irq ||
+                       new_serial.port != info->ioaddr)
+               return -EINVAL;
 
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                       return -EIO;
-       }
-       switch (cmd) {
-       case TCSBRK:            /* SVID version: non-zero arg --> no break */
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               tty_wait_until_sent(tty, 0);
-               if (!arg)
-                       mxser_send_break(info, HZ / 4); /* 1/4 second */
-               return 0;
-       case TCSBRKP:           /* support for POSIX tcsendbreak() */
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               tty_wait_until_sent(tty, 0);
-               mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
-               return 0;
-       case TIOCGSOFTCAR:
-               return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
-       case TIOCSSOFTCAR:
-               if (get_user(templ, (unsigned long __user *) argp))
-                       return -EFAULT;
-               arg = templ;
-               tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
-               return 0;
-       case TIOCGSERIAL:
-               return mxser_get_serial_info(info, argp);
-       case TIOCSSERIAL:
-               return mxser_set_serial_info(info, argp);
-       case TIOCSERGETLSR:     /* Get line status register */
-               return mxser_get_lsr_info(info, argp);
+       flags = info->flags & ASYNC_SPD_MASK;
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               if ((new_serial.baud_base != info->baud_base) ||
+                               (new_serial.close_delay != info->close_delay) ||
+                               ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
+                       return -EPERM;
+               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+                               (new_serial.flags & ASYNC_USR_MASK));
+       } else {
                /*
-                * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-                * - mask passed in arg for lines of interest
-                *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-                * Caller should use TIOCGICOUNT to see which one it was
+                * OK, past this point, all the error checking has been done.
+                * At this point, we start making changes.....
                 */
-       case TIOCMIWAIT:
-               spin_lock_irqsave(&info->slock, flags);
-               cnow = info->icount;    /* note the counters on entry */
-               spin_unlock_irqrestore(&info->slock, flags);
+               info->flags = ((info->flags & ~ASYNC_FLAGS) |
+                               (new_serial.flags & ASYNC_FLAGS));
+               info->close_delay = new_serial.close_delay * HZ / 100;
+               info->closing_wait = new_serial.closing_wait * HZ / 100;
+               info->tty->low_latency =
+                               (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+               info->tty->low_latency = 0;
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
+                               (new_serial.baud_base != info->baud_base ||
+                               new_serial.custom_divisor !=
+                               info->custom_divisor)) {
+                       baud = new_serial.baud_base / new_serial.custom_divisor;
+                       tty_encode_baud_rate(info->tty, baud, baud);
+               }
+       }
 
-               wait_event_interruptible(info->delta_msr_wait, ({
-                       cprev = cnow;
-                       spin_lock_irqsave(&info->slock, flags);
-                       cnow = info->icount;    /* atomic copy */
-                       spin_unlock_irqrestore(&info->slock, flags);
+       info->type = new_serial.type;
 
-                       ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                       ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                       ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                       ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
-               }));
-               break;
-               /*
-                * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-                * Return: write counters to the user passed counter struct
-                * NB: both 1->0 and 0->1 transitions are counted except for
-                *     RI where only 0->1 is counted.
-                */
-       case TIOCGICOUNT:
-               spin_lock_irqsave(&info->slock, flags);
-               cnow = info->icount;
-               spin_unlock_irqrestore(&info->slock, flags);
-               p_cuser = argp;
-               /* modified by casper 1/11/2000 */
-               if (put_user(cnow.frame, &p_cuser->frame))
-                       return -EFAULT;
-               if (put_user(cnow.brk, &p_cuser->brk))
-                       return -EFAULT;
-               if (put_user(cnow.overrun, &p_cuser->overrun))
-                       return -EFAULT;
-               if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
-                       return -EFAULT;
-               if (put_user(cnow.parity, &p_cuser->parity))
-                       return -EFAULT;
-               if (put_user(cnow.rx, &p_cuser->rx))
-                       return -EFAULT;
-               if (put_user(cnow.tx, &p_cuser->tx))
-                       return -EFAULT;
-               put_user(cnow.cts, &p_cuser->cts);
-               put_user(cnow.dsr, &p_cuser->dsr);
-               put_user(cnow.rng, &p_cuser->rng);
-               put_user(cnow.dcd, &p_cuser->dcd);
-               return 0;
-       case MOXA_HighSpeedOn:
-               return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
-       case MOXA_SDS_RSTICOUNTER: {
-                       info->mon_data.rxcnt = 0;
-                       info->mon_data.txcnt = 0;
-                       return 0;
-               }
-/* (above) added by James. */
-       case MOXA_ASPP_SETBAUD:{
-                       long baud;
-                       if (get_user(baud, (long __user *)argp))
-                               return -EFAULT;
-                       mxser_set_baud(info, baud);
-                       return 0;
+       process_txrx_fifo(info);
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               if (flags != (info->flags & ASYNC_SPD_MASK)) {
+                       spin_lock_irqsave(&info->slock, sl_flags);
+                       mxser_change_speed(info, NULL);
+                       spin_unlock_irqrestore(&info->slock, sl_flags);
                }
-       case MOXA_ASPP_GETBAUD:
-               if (copy_to_user(argp, &info->realbaud, sizeof(long)))
-                       return -EFAULT;
+       } else
+               retval = mxser_startup(info);
 
-               return 0;
+       return retval;
+}
 
-       case MOXA_ASPP_OQUEUE:{
-                       int len, lsr;
+/*
+ * mxser_get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space.
+ */
+static int mxser_get_lsr_info(struct mxser_port *info,
+               unsigned int __user *value)
+{
+       unsigned char status;
+       unsigned int result;
+       unsigned long flags;
 
-                       len = mxser_chars_in_buffer(tty);
+       spin_lock_irqsave(&info->slock, flags);
+       status = inb(info->ioaddr + UART_LSR);
+       spin_unlock_irqrestore(&info->slock, flags);
+       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+       return put_user(result, value);
+}
 
-                       lsr = inb(info->base + UART_LSR) & UART_LSR_TEMT;
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void mxser_send_break(struct mxser_port *info, int duration)
+{
+       unsigned long flags;
 
-                       len += (lsr ? 0 : 1);
+       if (!info->ioaddr)
+               return;
+       set_current_state(TASK_INTERRUPTIBLE);
+       spin_lock_irqsave(&info->slock, flags);
+       outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
+               info->ioaddr + UART_LCR);
+       spin_unlock_irqrestore(&info->slock, flags);
+       schedule_timeout(duration);
+       spin_lock_irqsave(&info->slock, flags);
+       outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
+               info->ioaddr + UART_LCR);
+       spin_unlock_irqrestore(&info->slock, flags);
+}
 
-                       if (copy_to_user(argp, &len, sizeof(int)))
-                               return -EFAULT;
+static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       struct mxser_port *info = tty->driver_data;
+       unsigned char control, status;
+       unsigned long flags;
 
-                       return 0;
-               }
-       case MOXA_ASPP_MON: {
-                       int mcr, status;
 
-                       /* info->mon_data.ser_param = tty->termios->c_cflag; */
+       if (tty->index == MXSER_PORTS)
+               return -ENOIOCTLCMD;
+       if (test_bit(TTY_IO_ERROR, &tty->flags))
+               return -EIO;
 
-                       status = mxser_get_msr(info->base, 1, info->port, info);
-                       mxser_check_modem_status(info, status);
+       control = info->MCR;
 
-                       mcr = inb(info->base + UART_MCR);
-                       if (mcr & MOXA_MUST_MCR_XON_FLAG)
-                               info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
-                       else
-                               info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
+       spin_lock_irqsave(&info->slock, flags);
+       status = inb(info->ioaddr + UART_MSR);
+       if (status & UART_MSR_ANY_DELTA)
+               mxser_check_modem_status(info, status);
+       spin_unlock_irqrestore(&info->slock, flags);
+       return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
+                   ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+                   ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+                   ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+                   ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+                   ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+}
 
-                       if (mcr & MOXA_MUST_MCR_TX_XON)
-                               info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
-                       else
-                               info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
+static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
+               unsigned int set, unsigned int clear)
+{
+       struct mxser_port *info = tty->driver_data;
+       unsigned long flags;
 
-                       if (info->tty->hw_stopped)
-                               info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
-                       else
-                               info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
 
-                       if (copy_to_user(argp, &info->mon_data,
-                                       sizeof(struct mxser_mon)))
-                               return -EFAULT;
+       if (tty->index == MXSER_PORTS)
+               return -ENOIOCTLCMD;
+       if (test_bit(TTY_IO_ERROR, &tty->flags))
+               return -EIO;
 
-                       return 0;
-               }
+       spin_lock_irqsave(&info->slock, flags);
 
-       case MOXA_ASPP_LSTATUS: {
-                       if (copy_to_user(argp, &info->err_shadow,
-                                       sizeof(unsigned char)))
-                               return -EFAULT;
+       if (set & TIOCM_RTS)
+               info->MCR |= UART_MCR_RTS;
+       if (set & TIOCM_DTR)
+               info->MCR |= UART_MCR_DTR;
 
-                       info->err_shadow = 0;
-                       return 0;
-               }
-       case MOXA_SET_BAUD_METHOD: {
-                       int method;
+       if (clear & TIOCM_RTS)
+               info->MCR &= ~UART_MCR_RTS;
+       if (clear & TIOCM_DTR)
+               info->MCR &= ~UART_MCR_DTR;
 
-                       if (get_user(method, (int __user *)argp))
-                               return -EFAULT;
-                       mxser_set_baud_method[info->port] = method;
-                       if (copy_to_user(argp, &method, sizeof(int)))
-                               return -EFAULT;
+       outb(info->MCR, info->ioaddr + UART_MCR);
+       spin_unlock_irqrestore(&info->slock, flags);
+       return 0;
+}
 
-                       return 0;
-               }
-       default:
-               return -ENOIOCTLCMD;
+static int __init mxser_program_mode(int port)
+{
+       int id, i, j, n;
+
+       outb(0, port);
+       outb(0, port);
+       outb(0, port);
+       (void)inb(port);
+       (void)inb(port);
+       outb(0, port);
+       (void)inb(port);
+
+       id = inb(port + 1) & 0x1F;
+       if ((id != C168_ASIC_ID) &&
+                       (id != C104_ASIC_ID) &&
+                       (id != C102_ASIC_ID) &&
+                       (id != CI132_ASIC_ID) &&
+                       (id != CI134_ASIC_ID) &&
+                       (id != CI104J_ASIC_ID))
+               return -1;
+       for (i = 0, j = 0; i < 4; i++) {
+               n = inb(port + 2);
+               if (n == 'M') {
+                       j = 1;
+               } else if ((j == 1) && (n == 1)) {
+                       j = 2;
+                       break;
+               } else
+                       j = 0;
        }
-       return 0;
+       if (j != 2)
+               id = -2;
+       return id;
 }
 
-#ifndef CMSPAR
-#define        CMSPAR 010000000000
-#endif
+static void __init mxser_normal_mode(int port)
+{
+       int i, n;
+
+       outb(0xA5, port + 1);
+       outb(0x80, port + 3);
+       outb(12, port + 0);     /* 9600 bps */
+       outb(0, port + 1);
+       outb(0x03, port + 3);   /* 8 data bits */
+       outb(0x13, port + 4);   /* loop back mode */
+       for (i = 0; i < 16; i++) {
+               n = inb(port + 5);
+               if ((n & 0x61) == 0x60)
+                       break;
+               if ((n & 1) == 1)
+                       (void)inb(port);
+       }
+       outb(0x00, port + 4);
+}
+
+#define CHIP_SK        0x01    /* Serial Data Clock  in Eprom */
+#define CHIP_DO        0x02    /* Serial Data Output in Eprom */
+#define CHIP_CS        0x04    /* Serial Chip Select in Eprom */
+#define CHIP_DI        0x08    /* Serial Data Input  in Eprom */
+#define EN_CCMD        0x000   /* Chip's command register     */
+#define EN0_RSARLO     0x008   /* Remote start address reg 0  */
+#define EN0_RSARHI     0x009   /* Remote start address reg 1  */
+#define EN0_RCNTLO     0x00A   /* Remote byte count reg WR    */
+#define EN0_RCNTHI     0x00B   /* Remote byte count reg WR    */
+#define EN0_DCFG       0x00E   /* Data configuration reg WR   */
+#define EN0_PORT       0x010   /* Rcv missed frame error counter RD */
+#define ENC_PAGE0      0x000   /* Select page 0 of chip registers   */
+#define ENC_PAGE3      0x0C0   /* Select page 3 of chip registers   */
+static int __init mxser_read_register(int port, unsigned short *regs)
+{
+       int i, k, value, id;
+       unsigned int j;
+
+       id = mxser_program_mode(port);
+       if (id < 0)
+               return id;
+       for (i = 0; i < 14; i++) {
+               k = (i & 0x3F) | 0x180;
+               for (j = 0x100; j > 0; j >>= 1) {
+                       outb(CHIP_CS, port);
+                       if (k & j) {
+                               outb(CHIP_CS | CHIP_DO, port);
+                               outb(CHIP_CS | CHIP_DO | CHIP_SK, port);        /* A? bit of read */
+                       } else {
+                               outb(CHIP_CS, port);
+                               outb(CHIP_CS | CHIP_SK, port);  /* A? bit of read */
+                       }
+               }
+               (void)inb(port);
+               value = 0;
+               for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
+                       outb(CHIP_CS, port);
+                       outb(CHIP_CS | CHIP_SK, port);
+                       if (inb(port) & CHIP_DI)
+                               value |= j;
+               }
+               regs[i] = value;
+               outb(0, port);
+       }
+       mxser_normal_mode(port);
+       return id;
+}
 
 static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 {
-       int i, result, status;
+       struct mxser_port *port;
+       int result, status;
+       unsigned int i, j;
 
        switch (cmd) {
-       case MOXA_GET_CONF:
-               if (copy_to_user(argp, mxsercfg,
-                               sizeof(struct mxser_hwconf) * 4))
-                       return -EFAULT;
-               return 0;
        case MOXA_GET_MAJOR:
-               if (copy_to_user(argp, &ttymajor, sizeof(int)))
-                       return -EFAULT;
-               return 0;
-
-       case MOXA_GET_CUMAJOR:
-               if (copy_to_user(argp, &calloutmajor, sizeof(int)))
-                       return -EFAULT;
-               return 0;
+               return put_user(ttymajor, (int __user *)argp);
 
        case MOXA_CHKPORTENABLE:
                result = 0;
-               for (i = 0; i < MXSER_PORTS; i++) {
-                       if (mxvar_table[i].base)
-                               result |= (1 << i);
-               }
+
+               for (i = 0; i < MXSER_BOARDS; i++)
+                       for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
+                               if (mxser_boards[i].ports[j].ioaddr)
+                                       result |= (1 << i);
+
                return put_user(result, (unsigned long __user *)argp);
        case MOXA_GETDATACOUNT:
                if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
                        return -EFAULT;
                return 0;
        case MOXA_GETMSTATUS:
-               for (i = 0; i < MXSER_PORTS; i++) {
-                       GMStatus[i].ri = 0;
-                       if (!mxvar_table[i].base) {
-                               GMStatus[i].dcd = 0;
-                               GMStatus[i].dsr = 0;
-                               GMStatus[i].cts = 0;
-                               continue;
-                       }
+               for (i = 0; i < MXSER_BOARDS; i++)
+                       for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
+                               port = &mxser_boards[i].ports[j];
+
+                               GMStatus[i].ri = 0;
+                               if (!port->ioaddr) {
+                                       GMStatus[i].dcd = 0;
+                                       GMStatus[i].dsr = 0;
+                                       GMStatus[i].cts = 0;
+                                       continue;
+                               }
 
-                       if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios)
-                               GMStatus[i].cflag = mxvar_table[i].normal_termios.c_cflag;
-                       else
-                               GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag;
+                               if (!port->tty || !port->tty->termios)
+                                       GMStatus[i].cflag =
+                                               port->normal_termios.c_cflag;
+                               else
+                                       GMStatus[i].cflag =
+                                               port->tty->termios->c_cflag;
 
-                       status = inb(mxvar_table[i].base + UART_MSR);
-                       if (status & 0x80 /*UART_MSR_DCD */ )
-                               GMStatus[i].dcd = 1;
-                       else
-                               GMStatus[i].dcd = 0;
+                               status = inb(port->ioaddr + UART_MSR);
+                               if (status & 0x80 /*UART_MSR_DCD */ )
+                                       GMStatus[i].dcd = 1;
+                               else
+                                       GMStatus[i].dcd = 0;
 
-                       if (status & 0x20 /*UART_MSR_DSR */ )
-                               GMStatus[i].dsr = 1;
-                       else
-                               GMStatus[i].dsr = 0;
+                               if (status & 0x20 /*UART_MSR_DSR */ )
+                                       GMStatus[i].dsr = 1;
+                               else
+                                       GMStatus[i].dsr = 0;
 
 
-                       if (status & 0x10 /*UART_MSR_CTS */ )
-                               GMStatus[i].cts = 1;
-                       else
-                               GMStatus[i].cts = 0;
-               }
+                               if (status & 0x10 /*UART_MSR_CTS */ )
+                                       GMStatus[i].cts = 1;
+                               else
+                                       GMStatus[i].cts = 0;
+                       }
                if (copy_to_user(argp, GMStatus,
                                sizeof(struct mxser_mstatus) * MXSER_PORTS))
                        return -EFAULT;
                return 0;
        case MOXA_ASPP_MON_EXT: {
-                       int status;
-                       int opmode, p;
-                       int shiftbit;
-                       unsigned cflag, iflag;
-
-                       for (i = 0; i < MXSER_PORTS; i++) {
-                               if (!mxvar_table[i].base)
+               int p, shiftbit;
+               unsigned long opmode;
+               unsigned cflag, iflag;
+
+               for (i = 0; i < MXSER_BOARDS; i++)
+                       for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
+                               port = &mxser_boards[i].ports[j];
+                               if (!port->ioaddr)
                                        continue;
 
-                               status = mxser_get_msr(mxvar_table[i].base, 0,
-                                                       i, &(mxvar_table[i]));
-                               /*
-                               mxser_check_modem_status(&mxvar_table[i],
-                                                               status);
-                               */
+                               status = mxser_get_msr(port->ioaddr, 0, i);
+
                                if (status & UART_MSR_TERI)
-                                       mxvar_table[i].icount.rng++;
+                                       port->icount.rng++;
                                if (status & UART_MSR_DDSR)
-                                       mxvar_table[i].icount.dsr++;
+                                       port->icount.dsr++;
                                if (status & UART_MSR_DDCD)
-                                       mxvar_table[i].icount.dcd++;
+                                       port->icount.dcd++;
                                if (status & UART_MSR_DCTS)
-                                       mxvar_table[i].icount.cts++;
-
-                               mxvar_table[i].mon_data.modem_status = status;
-                               mon_data_ext.rx_cnt[i] = mxvar_table[i].mon_data.rxcnt;
-                               mon_data_ext.tx_cnt[i] = mxvar_table[i].mon_data.txcnt;
-                               mon_data_ext.up_rxcnt[i] = mxvar_table[i].mon_data.up_rxcnt;
-                               mon_data_ext.up_txcnt[i] = mxvar_table[i].mon_data.up_txcnt;
-                               mon_data_ext.modem_status[i] = mxvar_table[i].mon_data.modem_status;
-                               mon_data_ext.baudrate[i] = mxvar_table[i].realbaud;
-
-                               if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios) {
-                                       cflag = mxvar_table[i].normal_termios.c_cflag;
-                                       iflag = mxvar_table[i].normal_termios.c_iflag;
+                                       port->icount.cts++;
+
+                               port->mon_data.modem_status = status;
+                               mon_data_ext.rx_cnt[i] = port->mon_data.rxcnt;
+                               mon_data_ext.tx_cnt[i] = port->mon_data.txcnt;
+                               mon_data_ext.up_rxcnt[i] =
+                                       port->mon_data.up_rxcnt;
+                               mon_data_ext.up_txcnt[i] =
+                                       port->mon_data.up_txcnt;
+                               mon_data_ext.modem_status[i] =
+                                       port->mon_data.modem_status;
+                               mon_data_ext.baudrate[i] =
+                                       tty_get_baud_rate(port->tty);
+
+                               if (!port->tty || !port->tty->termios) {
+                                       cflag = port->normal_termios.c_cflag;
+                                       iflag = port->normal_termios.c_iflag;
                                } else {
-                                       cflag = mxvar_table[i].tty->termios->c_cflag;
-                                       iflag = mxvar_table[i].tty->termios->c_iflag;
+                                       cflag = port->tty->termios->c_cflag;
+                                       iflag = port->tty->termios->c_iflag;
                                }
 
                                mon_data_ext.databits[i] = cflag & CSIZE;
 
                                mon_data_ext.stopbits[i] = cflag & CSTOPB;
 
-                               mon_data_ext.parity[i] = cflag & (PARENB | PARODD | CMSPAR);
+                               mon_data_ext.parity[i] =
+                                       cflag & (PARENB | PARODD | CMSPAR);
 
                                mon_data_ext.flowctrl[i] = 0x00;
 
@@ -1600,101 +1576,260 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                                if (iflag & (IXON | IXOFF))
                                        mon_data_ext.flowctrl[i] |= 0x0C;
 
-                               if (mxvar_table[i].type == PORT_16550A)
+                               if (port->type == PORT_16550A)
                                        mon_data_ext.fifo[i] = 1;
                                else
                                        mon_data_ext.fifo[i] = 0;
 
                                p = i % 4;
                                shiftbit = p * 2;
-                               opmode = inb(mxvar_table[i].opmode_ioaddr) >> shiftbit;
+                               opmode = inb(port->opmode_ioaddr) >> shiftbit;
                                opmode &= OP_MODE_MASK;
 
                                mon_data_ext.iftype[i] = opmode;
 
                        }
-                       if (copy_to_user(argp, &mon_data_ext, sizeof(struct mxser_mon_ext)))
+                       if (copy_to_user(argp, &mon_data_ext,
+                                               sizeof(mon_data_ext)))
                                return -EFAULT;
 
                        return 0;
 
-               }
-       default:
+       } default:
                return -ENOIOCTLCMD;
        }
        return 0;
 }
 
-static void mxser_stoprx(struct tty_struct *tty)
+static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg,
+               struct async_icount *cprev)
 {
-       struct mxser_struct *info = tty->driver_data;
-       /* unsigned long flags; */
+       struct async_icount cnow;
+       unsigned long flags;
+       int ret;
 
-       info->ldisc_stop_rx = 1;
-       if (I_IXOFF(tty)) {
-               /* MX_LOCK(&info->slock); */
-               /* following add by Victor Yu. 09-02-2002 */
-               if (info->IsMoxaMustChipFlag) {
-                       info->IER &= ~MOXA_MUST_RECV_ISR;
-                       outb(info->IER, info->base + UART_IER);
-               } else {
-                       /* above add by Victor Yu. 09-02-2002 */
-                       info->x_char = STOP_CHAR(tty);
-                       /* mask by Victor Yu. 09-02-2002 */
-                       /* outb(info->IER, 0); */
-                       outb(0, info->base + UART_IER);
-                       info->IER |= UART_IER_THRI;
-                       /* force Tx interrupt */
-                       outb(info->IER, info->base + UART_IER);
-               }               /* add by Victor Yu. 09-02-2002 */
-               /* MX_UNLOCK(&info->slock); */
-       }
+       spin_lock_irqsave(&info->slock, flags);
+       cnow = info->icount;    /* atomic copy */
+       spin_unlock_irqrestore(&info->slock, flags);
 
-       if (info->tty->termios->c_cflag & CRTSCTS) {
-               /* MX_LOCK(&info->slock); */
-               info->MCR &= ~UART_MCR_RTS;
-               outb(info->MCR, info->base + UART_MCR);
-               /* MX_UNLOCK(&info->slock); */
-       }
-}
+       ret =   ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
+               ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
+               ((arg & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
+               ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
 
-static void mxser_startrx(struct tty_struct *tty)
-{
-       struct mxser_struct *info = tty->driver_data;
-       /* unsigned long flags; */
+       *cprev = cnow;
 
-       info->ldisc_stop_rx = 0;
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else {
-                       /* MX_LOCK(&info->slock); */
+       return ret;
+}
 
-                       /* following add by Victor Yu. 09-02-2002 */
-                       if (info->IsMoxaMustChipFlag) {
-                               info->IER |= MOXA_MUST_RECV_ISR;
-                               outb(info->IER, info->base + UART_IER);
-                       } else {
-                               /* above add by Victor Yu. 09-02-2002 */
+static int mxser_ioctl(struct tty_struct *tty, struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       struct mxser_port *info = tty->driver_data;
+       struct async_icount cnow;
+       struct serial_icounter_struct __user *p_cuser;
+       unsigned long flags;
+       void __user *argp = (void __user *)arg;
+       int retval;
 
-                               info->x_char = START_CHAR(tty);
-                               /* mask by Victor Yu. 09-02-2002 */
-                               /* outb(info->IER, 0); */
-                               /* add by Victor Yu. 09-02-2002 */
-                               outb(0, info->base + UART_IER);
-                               /* force Tx interrupt */
-                               info->IER |= UART_IER_THRI;
-                               outb(info->IER, info->base + UART_IER);
-                       }       /* add by Victor Yu. 09-02-2002 */
-                       /* MX_UNLOCK(&info->slock); */
+       if (tty->index == MXSER_PORTS)
+               return mxser_ioctl_special(cmd, argp);
+
+       if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
+               int p;
+               unsigned long opmode;
+               static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
+               int shiftbit;
+               unsigned char val, mask;
+
+               p = tty->index % 4;
+               if (cmd == MOXA_SET_OP_MODE) {
+                       if (get_user(opmode, (int __user *) argp))
+                               return -EFAULT;
+                       if (opmode != RS232_MODE &&
+                                       opmode != RS485_2WIRE_MODE &&
+                                       opmode != RS422_MODE &&
+                                       opmode != RS485_4WIRE_MODE)
+                               return -EFAULT;
+                       mask = ModeMask[p];
+                       shiftbit = p * 2;
+                       val = inb(info->opmode_ioaddr);
+                       val &= mask;
+                       val |= (opmode << shiftbit);
+                       outb(val, info->opmode_ioaddr);
+               } else {
+                       shiftbit = p * 2;
+                       opmode = inb(info->opmode_ioaddr) >> shiftbit;
+                       opmode &= OP_MODE_MASK;
+                       if (put_user(opmode, (int __user *)argp))
+                               return -EFAULT;
+               }
+               return 0;
+       }
+
+       if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
+                       test_bit(TTY_IO_ERROR, &tty->flags))
+               return -EIO;
+
+       switch (cmd) {
+       case TCSBRK:            /* SVID version: non-zero arg --> no break */
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+               tty_wait_until_sent(tty, 0);
+               if (!arg)
+                       mxser_send_break(info, HZ / 4); /* 1/4 second */
+               return 0;
+       case TCSBRKP:           /* support for POSIX tcsendbreak() */
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+               tty_wait_until_sent(tty, 0);
+               mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
+               return 0;
+       case TIOCGSOFTCAR:
+               return put_user(!!C_CLOCAL(tty), (unsigned long __user *)argp);
+       case TIOCSSOFTCAR:
+               if (get_user(arg, (unsigned long __user *)argp))
+                       return -EFAULT;
+               tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+               return 0;
+       case TIOCGSERIAL:
+               return mxser_get_serial_info(info, argp);
+       case TIOCSSERIAL:
+               return mxser_set_serial_info(info, argp);
+       case TIOCSERGETLSR:     /* Get line status register */
+               return mxser_get_lsr_info(info, argp);
+               /*
+                * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+                * - mask passed in arg for lines of interest
+                *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+                * Caller should use TIOCGICOUNT to see which one it was
+                */
+       case TIOCMIWAIT:
+               spin_lock_irqsave(&info->slock, flags);
+               cnow = info->icount;    /* note the counters on entry */
+               spin_unlock_irqrestore(&info->slock, flags);
+
+               return wait_event_interruptible(info->delta_msr_wait,
+                               mxser_cflags_changed(info, arg, &cnow));
+       /*
+        * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+        * Return: write counters to the user passed counter struct
+        * NB: both 1->0 and 0->1 transitions are counted except for
+        *     RI where only 0->1 is counted.
+        */
+       case TIOCGICOUNT:
+               spin_lock_irqsave(&info->slock, flags);
+               cnow = info->icount;
+               spin_unlock_irqrestore(&info->slock, flags);
+               p_cuser = argp;
+               if (put_user(cnow.frame, &p_cuser->frame))
+                       return -EFAULT;
+               if (put_user(cnow.brk, &p_cuser->brk))
+                       return -EFAULT;
+               if (put_user(cnow.overrun, &p_cuser->overrun))
+                       return -EFAULT;
+               if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
+                       return -EFAULT;
+               if (put_user(cnow.parity, &p_cuser->parity))
+                       return -EFAULT;
+               if (put_user(cnow.rx, &p_cuser->rx))
+                       return -EFAULT;
+               if (put_user(cnow.tx, &p_cuser->tx))
+                       return -EFAULT;
+               put_user(cnow.cts, &p_cuser->cts);
+               put_user(cnow.dsr, &p_cuser->dsr);
+               put_user(cnow.rng, &p_cuser->rng);
+               put_user(cnow.dcd, &p_cuser->dcd);
+               return 0;
+       case MOXA_HighSpeedOn:
+               return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
+       case MOXA_SDS_RSTICOUNTER:
+               info->mon_data.rxcnt = 0;
+               info->mon_data.txcnt = 0;
+               return 0;
+
+       case MOXA_ASPP_OQUEUE:{
+               int len, lsr;
+
+               len = mxser_chars_in_buffer(tty);
+
+               lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
+
+               len += (lsr ? 0 : 1);
+
+               return put_user(len, (int __user *)argp);
+       }
+       case MOXA_ASPP_MON: {
+               int mcr, status;
+
+               status = mxser_get_msr(info->ioaddr, 1, tty->index);
+               mxser_check_modem_status(info, status);
+
+               mcr = inb(info->ioaddr + UART_MCR);
+               if (mcr & MOXA_MUST_MCR_XON_FLAG)
+                       info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
+               else
+                       info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
+
+               if (mcr & MOXA_MUST_MCR_TX_XON)
+                       info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
+               else
+                       info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
+
+               if (info->tty->hw_stopped)
+                       info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
+               else
+                       info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
+
+               if (copy_to_user(argp, &info->mon_data,
+                               sizeof(struct mxser_mon)))
+                       return -EFAULT;
+
+               return 0;
+       }
+       case MOXA_ASPP_LSTATUS: {
+               if (put_user(info->err_shadow, (unsigned char __user *)argp))
+                       return -EFAULT;
+
+               info->err_shadow = 0;
+               return 0;
+       }
+       case MOXA_SET_BAUD_METHOD: {
+               int method;
+
+               if (get_user(method, (int __user *)argp))
+                       return -EFAULT;
+               mxser_set_baud_method[tty->index] = method;
+               return put_user(method, (int __user *)argp);
+       }
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static void mxser_stoprx(struct tty_struct *tty)
+{
+       struct mxser_port *info = tty->driver_data;
+
+       info->ldisc_stop_rx = 1;
+       if (I_IXOFF(tty)) {
+               if (info->board->chip_flag) {
+                       info->IER &= ~MOXA_MUST_RECV_ISR;
+                       outb(info->IER, info->ioaddr + UART_IER);
+               } else {
+                       info->x_char = STOP_CHAR(tty);
+                       outb(0, info->ioaddr + UART_IER);
+                       info->IER |= UART_IER_THRI;
+                       outb(info->IER, info->ioaddr + UART_IER);
                }
        }
 
        if (info->tty->termios->c_cflag & CRTSCTS) {
-               /* MX_LOCK(&info->slock); */
-               info->MCR |= UART_MCR_RTS;
-               outb(info->MCR, info->base + UART_MCR);
-               /* MX_UNLOCK(&info->slock); */
+               info->MCR &= ~UART_MCR_RTS;
+               outb(info->MCR, info->ioaddr + UART_MCR);
        }
 }
 
@@ -1704,51 +1839,34 @@ static void mxser_startrx(struct tty_struct *tty)
  */
 static void mxser_throttle(struct tty_struct *tty)
 {
-       /* struct mxser_struct *info = tty->driver_data; */
-       /* unsigned long flags; */
-
-       /* MX_LOCK(&info->slock); */
        mxser_stoprx(tty);
-       /* MX_UNLOCK(&info->slock); */
 }
 
 static void mxser_unthrottle(struct tty_struct *tty)
 {
-       /* struct mxser_struct *info = tty->driver_data; */
-       /* unsigned long flags; */
-
-       /* MX_LOCK(&info->slock); */
-       mxser_startrx(tty);
-       /* MX_UNLOCK(&info->slock); */
-}
-
-static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct mxser_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       mxser_change_speed(info, old_termios);
-
-       if ((old_termios->c_cflag & CRTSCTS) &&
-                       !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               mxser_start(tty);
-       }
-
-/* Handle sw stopped */
-       if ((old_termios->c_iflag & IXON) &&
-                       !(tty->termios->c_iflag & IXON)) {
-               tty->stopped = 0;
+       struct mxser_port *info = tty->driver_data;
 
-               /* following add by Victor Yu. 09-02-2002 */
-               if (info->IsMoxaMustChipFlag) {
-                       spin_lock_irqsave(&info->slock, flags);
-                       DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
-                       spin_unlock_irqrestore(&info->slock, flags);
+       /* startrx */
+       info->ldisc_stop_rx = 0;
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else {
+                       if (info->board->chip_flag) {
+                               info->IER |= MOXA_MUST_RECV_ISR;
+                               outb(info->IER, info->ioaddr + UART_IER);
+                       } else {
+                               info->x_char = START_CHAR(tty);
+                               outb(0, info->ioaddr + UART_IER);
+                               info->IER |= UART_IER_THRI;
+                               outb(info->IER, info->ioaddr + UART_IER);
+                       }
                }
-               /* above add by Victor Yu. 09-02-2002 */
+       }
 
-               mxser_start(tty);
+       if (info->tty->termios->c_cflag & CRTSCTS) {
+               info->MCR |= UART_MCR_RTS;
+               outb(info->MCR, info->ioaddr + UART_MCR);
        }
 }
 
@@ -1760,36 +1878,67 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
  */
 static void mxser_stop(struct tty_struct *tty)
 {
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
        spin_lock_irqsave(&info->slock, flags);
        if (info->IER & UART_IER_THRI) {
                info->IER &= ~UART_IER_THRI;
-               outb(info->IER, info->base + UART_IER);
+               outb(info->IER, info->ioaddr + UART_IER);
        }
        spin_unlock_irqrestore(&info->slock, flags);
 }
 
 static void mxser_start(struct tty_struct *tty)
 {
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
        spin_lock_irqsave(&info->slock, flags);
-       if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
+       if (info->xmit_cnt && info->xmit_buf) {
+               outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
                info->IER |= UART_IER_THRI;
-               outb(info->IER, info->base + UART_IER);
+               outb(info->IER, info->ioaddr + UART_IER);
        }
        spin_unlock_irqrestore(&info->slock, flags);
 }
 
+static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+       struct mxser_port *info = tty->driver_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->slock, flags);
+       mxser_change_speed(info, old_termios);
+       spin_unlock_irqrestore(&info->slock, flags);
+
+       if ((old_termios->c_cflag & CRTSCTS) &&
+                       !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               mxser_start(tty);
+       }
+
+       /* Handle sw stopped */
+       if ((old_termios->c_iflag & IXON) &&
+                       !(tty->termios->c_iflag & IXON)) {
+               tty->stopped = 0;
+
+               if (info->board->chip_flag) {
+                       spin_lock_irqsave(&info->slock, flags);
+                       DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+                       spin_unlock_irqrestore(&info->slock, flags);
+               }
+
+               mxser_start(tty);
+       }
+}
+
 /*
  * mxser_wait_until_sent() --- wait until the transmitter is empty
  */
 static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
 {
-       struct mxser_struct *info = tty->driver_data;
+       struct mxser_port *info = tty->driver_data;
        unsigned long orig_jiffies, char_time;
        int lsr;
 
@@ -1830,1151 +1979,450 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
                timeout, char_time);
        printk("jiff=%lu...", jiffies);
 #endif
-       while (!((lsr = inb(info->base + UART_LSR)) & UART_LSR_TEMT)) {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
-               schedule_timeout_interruptible(char_time);
-               if (signal_pending(current))
-                       break;
-               if (timeout && time_after(jiffies, orig_jiffies + timeout))
-                       break;
-       }
-       set_current_state(TASK_RUNNING);
-
+       while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-
-
-/*
- * This routine is called by tty_hangup() when a hangup is signaled.
- */
-void mxser_hangup(struct tty_struct *tty)
-{
-       struct mxser_struct *info = tty->driver_data;
-
-       mxser_flush_buffer(tty);
-       mxser_shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-
-/* added by James 03-12-2004. */
-/*
- * mxser_rs_break() --- routine which turns the break handling on or off
- */
-static void mxser_rs_break(struct tty_struct *tty, int break_state)
-{
-       struct mxser_struct *info = tty->driver_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->slock, flags);
-       if (break_state == -1)
-               outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
-                       info->base + UART_LCR);
-       else
-               outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
-                       info->base + UART_LCR);
-       spin_unlock_irqrestore(&info->slock, flags);
-}
-
-/* (above) added by James. */
-
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t mxser_interrupt(int irq, void *dev_id)
-{
-       int status, iir, i;
-       struct mxser_struct *info;
-       struct mxser_struct *port;
-       int max, irqbits, bits, msr;
-       int pass_counter = 0;
-       int handled = IRQ_NONE;
-
-       port = NULL;
-       /* spin_lock(&gm_lock); */
-
-       for (i = 0; i < MXSER_BOARDS; i++) {
-               if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
-                       port = dev_id;
-                       break;
-               }
-       }
-
-       if (i == MXSER_BOARDS)
-               goto irq_stop;
-       if (port == 0)
-               goto irq_stop;
-       max = mxser_numports[mxsercfg[i].board_type - 1];
-       while (1) {
-               irqbits = inb(port->vector) & port->vectormask;
-               if (irqbits == port->vectormask)
-                       break;
-
-               handled = IRQ_HANDLED;
-               for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
-                       if (irqbits == port->vectormask)
-                               break;
-                       if (bits & irqbits)
-                               continue;
-                       info = port + i;
-
-                       /* following add by Victor Yu. 09-13-2002 */
-                       iir = inb(info->base + UART_IIR);
-                       if (iir & UART_IIR_NO_INT)
-                               continue;
-                       iir &= MOXA_MUST_IIR_MASK;
-                       if (!info->tty) {
-                               status = inb(info->base + UART_LSR);
-                               outb(0x27, info->base + UART_FCR);
-                               inb(info->base + UART_MSR);
-                               continue;
-                       }
-
-                       /* mask by Victor Yu. 09-13-2002
-                          if ( !info->tty ||
-                          (inb(info->base + UART_IIR) & UART_IIR_NO_INT) )
-                          continue;
-                        */
-                       /* mask by Victor Yu. 09-02-2002
-                          status = inb(info->base + UART_LSR) & info->read_status_mask;
-                        */
-
-                       /* following add by Victor Yu. 09-02-2002 */
-                       status = inb(info->base + UART_LSR);
-
-                       if (status & UART_LSR_PE)
-                               info->err_shadow |= NPPI_NOTIFY_PARITY;
-                       if (status & UART_LSR_FE)
-                               info->err_shadow |= NPPI_NOTIFY_FRAMING;
-                       if (status & UART_LSR_OE)
-                               info->err_shadow |= NPPI_NOTIFY_HW_OVERRUN;
-                       if (status & UART_LSR_BI)
-                               info->err_shadow |= NPPI_NOTIFY_BREAK;
-
-                       if (info->IsMoxaMustChipFlag) {
-                               /*
-                                  if ( (status & 0x02) && !(status & 0x01) ) {
-                                  outb(info->base+UART_FCR,  0x23);
-                                  continue;
-                                  }
-                                */
-                               if (iir == MOXA_MUST_IIR_GDA ||
-                                               iir == MOXA_MUST_IIR_RDA ||
-                                               iir == MOXA_MUST_IIR_RTO ||
-                                               iir == MOXA_MUST_IIR_LSR)
-                                       mxser_receive_chars(info, &status);
-
-                       } else {
-                               /* above add by Victor Yu. 09-02-2002 */
-
-                               status &= info->read_status_mask;
-                               if (status & UART_LSR_DR)
-                                       mxser_receive_chars(info, &status);
-                       }
-                       msr = inb(info->base + UART_MSR);
-                       if (msr & UART_MSR_ANY_DELTA) {
-                               mxser_check_modem_status(info, msr);
-                       }
-                       /* following add by Victor Yu. 09-13-2002 */
-                       if (info->IsMoxaMustChipFlag) {
-                               if ((iir == 0x02) && (status & UART_LSR_THRE)) {
-                                       mxser_transmit_chars(info);
-                               }
-                       } else {
-                               /* above add by Victor Yu. 09-13-2002 */
-
-                               if (status & UART_LSR_THRE) {
-/* 8-2-99 by William
-                           if ( info->x_char || (info->xmit_cnt > 0) )
-*/
-                                       mxser_transmit_chars(info);
-                               }
-                       }
-               }
-               if (pass_counter++ > MXSER_ISR_PASS_LIMIT) {
-                       break;  /* Prevent infinite loops */
-               }
-       }
-
-      irq_stop:
-       /* spin_unlock(&gm_lock); */
-       return handled;
-}
-
-static void mxser_receive_chars(struct mxser_struct *info, int *status)
-{
-       struct tty_struct *tty = info->tty;
-       unsigned char ch, gdl;
-       int ignored = 0;
-       int cnt = 0;
-       int recv_room;
-       int max = 256;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       recv_room = tty->receive_room;
-       if ((recv_room == 0) && (!info->ldisc_stop_rx)) {
-               /* mxser_throttle(tty); */
-               mxser_stoprx(tty);
-               /* return; */
-       }
-
-       /* following add by Victor Yu. 09-02-2002 */
-       if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
-
-               if (*status & UART_LSR_SPECIAL) {
-                       goto intr_old;
-               }
-               /* following add by Victor Yu. 02-11-2004 */
-               if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID &&
-                               (*status & MOXA_MUST_LSR_RERR))
-                       goto intr_old;
-               /* above add by Victor Yu. 02-14-2004 */
-               if (*status & MOXA_MUST_LSR_RERR)
-                       goto intr_old;
-
-               gdl = inb(info->base + MOXA_MUST_GDL_REGISTER);
-
-               /* add by Victor Yu. 02-11-2004 */
-               if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID)
-                       gdl &= MOXA_MUST_GDL_MASK;
-               if (gdl >= recv_room) {
-                       if (!info->ldisc_stop_rx) {
-                               /* mxser_throttle(tty); */
-                               mxser_stoprx(tty);
-                       }
-                       /* return; */
-               }
-               while (gdl--) {
-                       ch = inb(info->base + UART_RX);
-                       tty_insert_flip_char(tty, ch, 0);
-                       cnt++;
-                       /*
-                          if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
-                          mxser_stoprx(tty);
-                          info->stop_rx = 1;
-                          break;
-                          } */
-               }
-               goto end_intr;
-       }
- intr_old:
-       /* above add by Victor Yu. 09-02-2002 */
-
-       do {
-               if (max-- < 0)
-                       break;
-               /*
-                  if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
-                  mxser_stoprx(tty);
-                  info->stop_rx=1;
-                  break;
-                  }
-                */
-
-               ch = inb(info->base + UART_RX);
-               /* following add by Victor Yu. 09-02-2002 */
-               if (info->IsMoxaMustChipFlag && (*status & UART_LSR_OE) /*&& !(*status&UART_LSR_DR) */ )
-                       outb(0x23, info->base + UART_FCR);
-               *status &= info->read_status_mask;
-               /* above add by Victor Yu. 09-02-2002 */
-               if (*status & info->ignore_status_mask) {
-                       if (++ignored > 100)
-                               break;
-               } else {
-                       char flag = 0;
-                       if (*status & UART_LSR_SPECIAL) {
-                               if (*status & UART_LSR_BI) {
-                                       flag = TTY_BREAK;
-/* added by casper 1/11/2000 */
-                                       info->icount.brk++;
-/* */
-                                       if (info->flags & ASYNC_SAK)
-                                               do_SAK(tty);
-                               } else if (*status & UART_LSR_PE) {
-                                       flag = TTY_PARITY;
-/* added by casper 1/11/2000 */
-                                       info->icount.parity++;
-/* */
-                               } else if (*status & UART_LSR_FE) {
-                                       flag = TTY_FRAME;
-/* added by casper 1/11/2000 */
-                                       info->icount.frame++;
-/* */
-                               } else if (*status & UART_LSR_OE) {
-                                       flag = TTY_OVERRUN;
-/* added by casper 1/11/2000 */
-                                       info->icount.overrun++;
-/* */
-                               }
-                       }
-                       tty_insert_flip_char(tty, ch, flag);
-                       cnt++;
-                       if (cnt >= recv_room) {
-                               if (!info->ldisc_stop_rx) {
-                                       /* mxser_throttle(tty); */
-                                       mxser_stoprx(tty);
-                               }
-                               break;
-                       }
-
-               }
-
-               /* following add by Victor Yu. 09-02-2002 */
-               if (info->IsMoxaMustChipFlag)
-                       break;
-               /* above add by Victor Yu. 09-02-2002 */
-
-               /* mask by Victor Yu. 09-02-2002
-                *status = inb(info->base + UART_LSR) & info->read_status_mask;
-                */
-               /* following add by Victor Yu. 09-02-2002 */
-               *status = inb(info->base + UART_LSR);
-               /* above add by Victor Yu. 09-02-2002 */
-       } while (*status & UART_LSR_DR);
-
-end_intr:              /* add by Victor Yu. 09-02-2002 */
-       mxvar_log.rxcnt[info->port] += cnt;
-       info->mon_data.rxcnt += cnt;
-       info->mon_data.up_rxcnt += cnt;
-       spin_unlock_irqrestore(&info->slock, flags);
-
-       tty_flip_buffer_push(tty);
-}
-
-static void mxser_transmit_chars(struct mxser_struct *info)
-{
-       int count, cnt;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       if (info->x_char) {
-               outb(info->x_char, info->base + UART_TX);
-               info->x_char = 0;
-               mxvar_log.txcnt[info->port]++;
-               info->mon_data.txcnt++;
-               info->mon_data.up_txcnt++;
-
-/* added by casper 1/11/2000 */
-               info->icount.tx++;
-/* */
-               spin_unlock_irqrestore(&info->slock, flags);
-               return;
-       }
-
-       if (info->xmit_buf == 0) {
-               spin_unlock_irqrestore(&info->slock, flags);
-               return;
-       }
-
-       if ((info->xmit_cnt <= 0) || info->tty->stopped ||
-                       (info->tty->hw_stopped &&
-                       (info->type != PORT_16550A) &&
-                       (!info->IsMoxaMustChipFlag))) {
-               info->IER &= ~UART_IER_THRI;
-               outb(info->IER, info->base + UART_IER);
-               spin_unlock_irqrestore(&info->slock, flags);
-               return;
-       }
-
-       cnt = info->xmit_cnt;
-       count = info->xmit_fifo_size;
-       do {
-               outb(info->xmit_buf[info->xmit_tail++],
-                       info->base + UART_TX);
-               info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);
-               if (--info->xmit_cnt <= 0)
-                       break;
-       } while (--count > 0);
-       mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);
-
-/* added by James 03-12-2004. */
-       info->mon_data.txcnt += (cnt - info->xmit_cnt);
-       info->mon_data.up_txcnt += (cnt - info->xmit_cnt);
-/* (above) added by James. */
-
-/* added by casper 1/11/2000 */
-       info->icount.tx += (cnt - info->xmit_cnt);
-/* */
-
-       if (info->xmit_cnt < WAKEUP_CHARS) {
-               set_bit(MXSER_EVENT_TXLOW, &info->event);
-               schedule_work(&info->tqueue);
-       }
-       if (info->xmit_cnt <= 0) {
-               info->IER &= ~UART_IER_THRI;
-               outb(info->IER, info->base + UART_IER);
-       }
-       spin_unlock_irqrestore(&info->slock, flags);
-}
-
-static void mxser_check_modem_status(struct mxser_struct *info, int status)
-{
-       /* update input line counters */
-       if (status & UART_MSR_TERI)
-               info->icount.rng++;
-       if (status & UART_MSR_DDSR)
-               info->icount.dsr++;
-       if (status & UART_MSR_DDCD)
-               info->icount.dcd++;
-       if (status & UART_MSR_DCTS)
-               info->icount.cts++;
-       info->mon_data.modem_status = status;
-       wake_up_interruptible(&info->delta_msr_wait);
-
-       if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-               if (status & UART_MSR_DCD)
-                       wake_up_interruptible(&info->open_wait);
-               schedule_work(&info->tqueue);
-       }
-
-       if (info->flags & ASYNC_CTS_FLOW) {
-               if (info->tty->hw_stopped) {
-                       if (status & UART_MSR_CTS) {
-                               info->tty->hw_stopped = 0;
-
-                               if ((info->type != PORT_16550A) &&
-                                               (!info->IsMoxaMustChipFlag)) {
-                                       info->IER |= UART_IER_THRI;
-                                       outb(info->IER, info->base + UART_IER);
-                               }
-                               set_bit(MXSER_EVENT_TXLOW, &info->event);
-                               schedule_work(&info->tqueue);                   }
-               } else {
-                       if (!(status & UART_MSR_CTS)) {
-                               info->tty->hw_stopped = 1;
-                               if ((info->type != PORT_16550A) &&
-                                               (!info->IsMoxaMustChipFlag)) {
-                                       info->IER &= ~UART_IER_THRI;
-                                       outb(info->IER, info->base + UART_IER);
-                               }
-                       }
-               }
-       }
-}
-
-static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, struct mxser_struct *info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int retval;
-       int do_clocal = 0;
-       unsigned long flags;
-
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->count is dropped by one, so that
-        * mxser_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&info->open_wait, &wait);
-
-       spin_lock_irqsave(&info->slock, flags);
-       if (!tty_hung_up_p(filp))
-               info->count--;
-       spin_unlock_irqrestore(&info->slock, flags);
-       info->blocked_open++;
-       while (1) {
-               spin_lock_irqsave(&info->slock, flags);
-               outb(inb(info->base + UART_MCR) |
-                       UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
-               spin_unlock_irqrestore(&info->slock, flags);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {
-                       if (info->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               if (!(info->flags & ASYNC_CLOSING) &&
-                               (do_clocal ||
-                               (inb(info->base + UART_MSR) & UART_MSR_DCD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               info->count++;
-       info->blocked_open--;
-       if (retval)
-               return retval;
-       info->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}
-
-static int mxser_startup(struct mxser_struct *info)
-{
-       unsigned long page;
-       unsigned long flags;
-
-       page = __get_free_page(GFP_KERNEL);
-       if (!page)
-               return -ENOMEM;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               free_page(page);
-               spin_unlock_irqrestore(&info->slock, flags);
-               return 0;
-       }
-
-       if (!info->base || !info->type) {
-               if (info->tty)
-                       set_bit(TTY_IO_ERROR, &info->tty->flags);
-               free_page(page);
-               spin_unlock_irqrestore(&info->slock, flags);
-               return 0;
-       }
-       if (info->xmit_buf)
-               free_page(page);
-       else
-               info->xmit_buf = (unsigned char *) page;
-
-       /*
-        * Clear the FIFO buffers and disable them
-        * (they will be reenabled in mxser_change_speed())
-        */
-       if (info->IsMoxaMustChipFlag)
-               outb((UART_FCR_CLEAR_RCVR |
-                       UART_FCR_CLEAR_XMIT |
-                       MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
-       else
-               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
-                       info->base + UART_FCR);
-
-       /*
-        * At this point there's no way the LSR could still be 0xFF;
-        * if it is, then bail out, because there's likely no UART
-        * here.
-        */
-       if (inb(info->base + UART_LSR) == 0xff) {
-               spin_unlock_irqrestore(&info->slock, flags);
-               if (capable(CAP_SYS_ADMIN)) {
-                       if (info->tty)
-                               set_bit(TTY_IO_ERROR, &info->tty->flags);
-                       return 0;
-               } else
-                       return -ENODEV;
-       }
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) inb(info->base + UART_LSR);
-       (void) inb(info->base + UART_RX);
-       (void) inb(info->base + UART_IIR);
-       (void) inb(info->base + UART_MSR);
-
-       /*
-        * Now, initialize the UART
-        */
-       outb(UART_LCR_WLEN8, info->base + UART_LCR);    /* reset DLAB */
-       info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-       outb(info->MCR, info->base + UART_MCR);
-
-       /*
-        * Finally, enable interrupts
-        */
-       info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-       /* info->IER = UART_IER_RLSI | UART_IER_RDI; */
-
-       /* following add by Victor Yu. 08-30-2002 */
-       if (info->IsMoxaMustChipFlag)
-               info->IER |= MOXA_MUST_IER_EGDAI;
-       /* above add by Victor Yu. 08-30-2002 */
-       outb(info->IER, info->base + UART_IER); /* enable interrupts */
-
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       (void) inb(info->base + UART_LSR);
-       (void) inb(info->base + UART_RX);
-       (void) inb(info->base + UART_IIR);
-       (void) inb(info->base + UART_MSR);
-
-       if (info->tty)
-               clear_bit(TTY_IO_ERROR, &info->tty->flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-       /*
-        * and set the speed of the serial port
-        */
-       spin_unlock_irqrestore(&info->slock, flags);
-       mxser_change_speed(info, NULL);
-
-       info->flags |= ASYNC_INITIALIZED;
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts maybe disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void mxser_shutdown(struct mxser_struct *info)
-{
-       unsigned long flags;
-
-       if (!(info->flags & ASYNC_INITIALIZED))
-               return;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       /*
-        * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
-        * here so the queue might never be waken up
-        */
-       wake_up_interruptible(&info->delta_msr_wait);
-
-       /*
-        * Free the IRQ, if necessary
-        */
-       if (info->xmit_buf) {
-               free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = NULL;
-       }
-
-       info->IER = 0;
-       outb(0x00, info->base + UART_IER);
-
-       if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
-               info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
-       outb(info->MCR, info->base + UART_MCR);
-
-       /* clear Rx/Tx FIFO's */
-       /* following add by Victor Yu. 08-30-2002 */
-       if (info->IsMoxaMustChipFlag)
-               outb((UART_FCR_CLEAR_RCVR |
-                       UART_FCR_CLEAR_XMIT |
-                       MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
-       else
-               /* above add by Victor Yu. 08-30-2002 */
-               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
-                       info->base + UART_FCR);
-
-       /* read data port to reset things */
-       (void) inb(info->base + UART_RX);
-
-       if (info->tty)
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-       info->flags &= ~ASYNC_INITIALIZED;
-
-       /* following add by Victor Yu. 09-23-2002 */
-       if (info->IsMoxaMustChipFlag)
-               SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base);
-       /* above add by Victor Yu. 09-23-2002 */
-
-       spin_unlock_irqrestore(&info->slock, flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static int mxser_change_speed(struct mxser_struct *info, struct ktermios *old_termios)
-{
-       unsigned cflag, cval, fcr;
-       int ret = 0;
-       unsigned char status;
-       long baud;
-       unsigned long flags;
-
-       if (!info->tty || !info->tty->termios)
-               return ret;
-       cflag = info->tty->termios->c_cflag;
-       if (!(info->base))
-               return ret;
-
-#ifndef B921600
-#define B921600 (B460800 +1)
-#endif
-       if (mxser_set_baud_method[info->port] == 0) {
-               baud = tty_get_baud_rate(info->tty);
-               mxser_set_baud(info, baud);
-       }
-
-       /* byte size and parity */
-       switch (cflag & CSIZE) {
-       case CS5:
-               cval = 0x00;
-               break;
-       case CS6:
-               cval = 0x01;
-               break;
-       case CS7:
-               cval = 0x02;
-               break;
-       case CS8:
-               cval = 0x03;
-               break;
-       default:
-               cval = 0x00;
-               break;          /* too keep GCC shut... */
-       }
-       if (cflag & CSTOPB)
-               cval |= 0x04;
-       if (cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-       if (cflag & CMSPAR)
-               cval |= UART_LCR_SPAR;
-
-       if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
-               if (info->IsMoxaMustChipFlag) {
-                       fcr = UART_FCR_ENABLE_FIFO;
-                       fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
-                       SET_MOXA_MUST_FIFO_VALUE(info);
-               } else
-                       fcr = 0;
-       } else {
-               fcr = UART_FCR_ENABLE_FIFO;
-               /* following add by Victor Yu. 08-30-2002 */
-               if (info->IsMoxaMustChipFlag) {
-                       fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
-                       SET_MOXA_MUST_FIFO_VALUE(info);
-               } else {
-                       /* above add by Victor Yu. 08-30-2002 */
-                       switch (info->rx_trigger) {
-                       case 1:
-                               fcr |= UART_FCR_TRIGGER_1;
-                               break;
-                       case 4:
-                               fcr |= UART_FCR_TRIGGER_4;
-                               break;
-                       case 8:
-                               fcr |= UART_FCR_TRIGGER_8;
-                               break;
-                       default:
-                               fcr |= UART_FCR_TRIGGER_14;
-                               break;
-                       }
-               }
-       }
-
-       /* CTS flow control flag and modem status interrupts */
-       info->IER &= ~UART_IER_MSI;
-       info->MCR &= ~UART_MCR_AFE;
-       if (cflag & CRTSCTS) {
-               info->flags |= ASYNC_CTS_FLOW;
-               info->IER |= UART_IER_MSI;
-               if ((info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
-                       info->MCR |= UART_MCR_AFE;
-               } else {
-                       status = inb(info->base + UART_MSR);
-                       if (info->tty->hw_stopped) {
-                               if (status & UART_MSR_CTS) {
-                                       info->tty->hw_stopped = 0;
-                                       if ((info->type != PORT_16550A) &&
-                                                       (!info->IsMoxaMustChipFlag)) {
-                                               info->IER |= UART_IER_THRI;
-                                               outb(info->IER, info->base + UART_IER);
-                                       }
-                                       set_bit(MXSER_EVENT_TXLOW, &info->event);
-                                       schedule_work(&info->tqueue);                           }
-                       } else {
-                               if (!(status & UART_MSR_CTS)) {
-                                       info->tty->hw_stopped = 1;
-                                       if ((info->type != PORT_16550A) &&
-                                                       (!info->IsMoxaMustChipFlag)) {
-                                               info->IER &= ~UART_IER_THRI;
-                                               outb(info->IER, info->base + UART_IER);
-                                       }
-                               }
-                       }
-               }
-       } else {
-               info->flags &= ~ASYNC_CTS_FLOW;
-       }
-       outb(info->MCR, info->base + UART_MCR);
-       if (cflag & CLOCAL) {
-               info->flags &= ~ASYNC_CHECK_CD;
-       } else {
-               info->flags |= ASYNC_CHECK_CD;
-               info->IER |= UART_IER_MSI;
-       }
-       outb(info->IER, info->base + UART_IER);
-
-       /*
-        * Set up parity check flag
-        */
-       info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (I_INPCK(info->tty))
-               info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
-               info->read_status_mask |= UART_LSR_BI;
-
-       info->ignore_status_mask = 0;
-
-       if (I_IGNBRK(info->tty)) {
-               info->ignore_status_mask |= UART_LSR_BI;
-               info->read_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignore parity and break indicators, ignore
-                * overruns too.  (For real raw support).
-                */
-               if (I_IGNPAR(info->tty)) {
-                       info->ignore_status_mask |=
-                                               UART_LSR_OE |
-                                               UART_LSR_PE |
-                                               UART_LSR_FE;
-                       info->read_status_mask |=
-                                               UART_LSR_OE |
-                                               UART_LSR_PE |
-                                               UART_LSR_FE;
-               }
-       }
-       /* following add by Victor Yu. 09-02-2002 */
-       if (info->IsMoxaMustChipFlag) {
-               spin_lock_irqsave(&info->slock, flags);
-               SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty));
-               SET_MOXA_MUST_XOFF1_VALUE(info->base, STOP_CHAR(info->tty));
-               if (I_IXON(info->tty)) {
-                       ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
-               } else {
-                       DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
-               }
-               if (I_IXOFF(info->tty)) {
-                       ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base);
-               } else {
-                       DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base);
-               }
-               /*
-                  if ( I_IXANY(info->tty) ) {
-                  info->MCR |= MOXA_MUST_MCR_XON_ANY;
-                  ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base);
-                  } else {
-                  info->MCR &= ~MOXA_MUST_MCR_XON_ANY;
-                  DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base);
-                  }
-                */
-               spin_unlock_irqrestore(&info->slock, flags);
+               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+               schedule_timeout_interruptible(char_time);
+               if (signal_pending(current))
+                       break;
+               if (timeout && time_after(jiffies, orig_jiffies + timeout))
+                       break;
        }
-       /* above add by Victor Yu. 09-02-2002 */
+       set_current_state(TASK_RUNNING);
 
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
 
-       outb(fcr, info->base + UART_FCR);       /* set fcr */
-       outb(cval, info->base + UART_LCR);
+/*
+ * This routine is called by tty_hangup() when a hangup is signaled.
+ */
+static void mxser_hangup(struct tty_struct *tty)
+{
+       struct mxser_port *info = tty->driver_data;
 
-       return ret;
+       mxser_flush_buffer(tty);
+       mxser_shutdown(info);
+       info->event = 0;
+       info->count = 0;
+       info->flags &= ~ASYNC_NORMAL_ACTIVE;
+       info->tty = NULL;
+       wake_up_interruptible(&info->open_wait);
 }
 
-
-static int mxser_set_baud(struct mxser_struct *info, long newspd)
+/*
+ * mxser_rs_break() --- routine which turns the break handling on or off
+ */
+static void mxser_rs_break(struct tty_struct *tty, int break_state)
 {
-       int quot = 0;
-       unsigned char cval;
-       int ret = 0;
+       struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
-       if (!info->tty || !info->tty->termios)
-               return ret;
+       spin_lock_irqsave(&info->slock, flags);
+       if (break_state == -1)
+               outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
+                       info->ioaddr + UART_LCR);
+       else
+               outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
+                       info->ioaddr + UART_LCR);
+       spin_unlock_irqrestore(&info->slock, flags);
+}
 
-       if (!(info->base))
-               return ret;
+static void mxser_receive_chars(struct mxser_port *port, int *status)
+{
+       struct tty_struct *tty = port->tty;
+       unsigned char ch, gdl;
+       int ignored = 0;
+       int cnt = 0;
+       int recv_room;
+       int max = 256;
 
-       if (newspd > info->MaxCanSetBaudRate)
-               return 0;
+       recv_room = tty->receive_room;
+       if ((recv_room == 0) && (!port->ldisc_stop_rx))
+               mxser_stoprx(tty);
 
-       info->realbaud = newspd;
-       if (newspd == 134) {
-               quot = (2 * info->baud_base / 269);
-       } else if (newspd) {
-               quot = info->baud_base / newspd;
-               if (quot == 0)
-                       quot = 1;
-       } else {
-               quot = 0;
-       }
+       if (port->board->chip_flag != MOXA_OTHER_UART) {
 
-       info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
-       info->timeout += HZ / 50;       /* Add .02 seconds of slop */
+               if (*status & UART_LSR_SPECIAL)
+                       goto intr_old;
+               if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
+                               (*status & MOXA_MUST_LSR_RERR))
+                       goto intr_old;
+               if (*status & MOXA_MUST_LSR_RERR)
+                       goto intr_old;
 
-       if (quot) {
-               spin_lock_irqsave(&info->slock, flags);
-               info->MCR |= UART_MCR_DTR;
-               outb(info->MCR, info->base + UART_MCR);
-               spin_unlock_irqrestore(&info->slock, flags);
-       } else {
-               spin_lock_irqsave(&info->slock, flags);
-               info->MCR &= ~UART_MCR_DTR;
-               outb(info->MCR, info->base + UART_MCR);
-               spin_unlock_irqrestore(&info->slock, flags);
-               return ret;
+               gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
+
+               if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
+                       gdl &= MOXA_MUST_GDL_MASK;
+               if (gdl >= recv_room) {
+                       if (!port->ldisc_stop_rx)
+                               mxser_stoprx(tty);
+               }
+               while (gdl--) {
+                       ch = inb(port->ioaddr + UART_RX);
+                       tty_insert_flip_char(tty, ch, 0);
+                       cnt++;
+               }
+               goto end_intr;
        }
+intr_old:
+
+       do {
+               if (max-- < 0)
+                       break;
 
-       cval = inb(info->base + UART_LCR);
+               ch = inb(port->ioaddr + UART_RX);
+               if (port->board->chip_flag && (*status & UART_LSR_OE))
+                       outb(0x23, port->ioaddr + UART_FCR);
+               *status &= port->read_status_mask;
+               if (*status & port->ignore_status_mask) {
+                       if (++ignored > 100)
+                               break;
+               } else {
+                       char flag = 0;
+                       if (*status & UART_LSR_SPECIAL) {
+                               if (*status & UART_LSR_BI) {
+                                       flag = TTY_BREAK;
+                                       port->icount.brk++;
 
-       outb(cval | UART_LCR_DLAB, info->base + UART_LCR);      /* set DLAB */
+                                       if (port->flags & ASYNC_SAK)
+                                               do_SAK(tty);
+                               } else if (*status & UART_LSR_PE) {
+                                       flag = TTY_PARITY;
+                                       port->icount.parity++;
+                               } else if (*status & UART_LSR_FE) {
+                                       flag = TTY_FRAME;
+                                       port->icount.frame++;
+                               } else if (*status & UART_LSR_OE) {
+                                       flag = TTY_OVERRUN;
+                                       port->icount.overrun++;
+                               } else
+                                       flag = TTY_BREAK;
+                       }
+                       tty_insert_flip_char(tty, ch, flag);
+                       cnt++;
+                       if (cnt >= recv_room) {
+                               if (!port->ldisc_stop_rx)
+                                       mxser_stoprx(tty);
+                               break;
+                       }
 
-       outb(quot & 0xff, info->base + UART_DLL);       /* LS of divisor */
-       outb(quot >> 8, info->base + UART_DLM); /* MS of divisor */
-       outb(cval, info->base + UART_LCR);      /* reset DLAB */
+               }
 
+               if (port->board->chip_flag)
+                       break;
 
-       return ret;
-}
+               *status = inb(port->ioaddr + UART_LSR);
+       } while (*status & UART_LSR_DR);
 
-/*
- * ------------------------------------------------------------
- * friends of mxser_ioctl()
- * ------------------------------------------------------------
- */
-static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct __user *retinfo)
-{
-       struct serial_struct tmp;
+end_intr:
+       mxvar_log.rxcnt[port->tty->index] += cnt;
+       port->mon_data.rxcnt += cnt;
+       port->mon_data.up_rxcnt += cnt;
 
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->port;
-       tmp.port = info->base;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       tmp.hub6 = 0;
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
+       /*
+        * We are called from an interrupt context with &port->slock
+        * being held. Drop it temporarily in order to prevent
+        * recursive locking.
+        */
+       spin_unlock(&port->slock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&port->slock);
 }
 
-static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct __user *new_info)
+static void mxser_transmit_chars(struct mxser_port *port)
 {
-       struct serial_struct new_serial;
-       unsigned int flags;
-       int retval = 0;
-
-       if (!new_info || !info->base)
-               return -EFAULT;
-       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
-               return -EFAULT;
+       int count, cnt;
 
-       if ((new_serial.irq != info->irq) ||
-                       (new_serial.port != info->base) ||
-                       (new_serial.custom_divisor != info->custom_divisor) ||
-                       (new_serial.baud_base != info->baud_base))
-               return -EPERM;
+       if (port->x_char) {
+               outb(port->x_char, port->ioaddr + UART_TX);
+               port->x_char = 0;
+               mxvar_log.txcnt[port->tty->index]++;
+               port->mon_data.txcnt++;
+               port->mon_data.up_txcnt++;
+               port->icount.tx++;
+               return;
+       }
 
-       flags = info->flags & ASYNC_SPD_MASK;
+       if (port->xmit_buf == NULL)
+               return;
 
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.baud_base != info->baud_base) ||
-                               (new_serial.close_delay != info->close_delay) ||
-                               ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-                               (new_serial.flags & ASYNC_USR_MASK));
-       } else {
-               /*
-                * OK, past this point, all the error checking has been done.
-                * At this point, we start making changes.....
-                */
-               info->flags = ((info->flags & ~ASYNC_FLAGS) |
-                               (new_serial.flags & ASYNC_FLAGS));
-               info->close_delay = new_serial.close_delay * HZ / 100;
-               info->closing_wait = new_serial.closing_wait * HZ / 100;
-               info->tty->low_latency =
-                               (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-               info->tty->low_latency = 0;     /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */
+       if ((port->xmit_cnt <= 0) || port->tty->stopped ||
+                       (port->tty->hw_stopped &&
+                       (port->type != PORT_16550A) &&
+                       (!port->board->chip_flag))) {
+               port->IER &= ~UART_IER_THRI;
+               outb(port->IER, port->ioaddr + UART_IER);
+               return;
        }
 
-       /* added by casper, 3/17/2000, for mouse */
-       info->type = new_serial.type;
+       cnt = port->xmit_cnt;
+       count = port->xmit_fifo_size;
+       do {
+               outb(port->xmit_buf[port->xmit_tail++],
+                       port->ioaddr + UART_TX);
+               port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
+               if (--port->xmit_cnt <= 0)
+                       break;
+       } while (--count > 0);
+       mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt);
 
-       process_txrx_fifo(info);
+       port->mon_data.txcnt += (cnt - port->xmit_cnt);
+       port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
+       port->icount.tx += (cnt - port->xmit_cnt);
 
-       if (info->flags & ASYNC_INITIALIZED) {
-               if (flags != (info->flags & ASYNC_SPD_MASK)) {
-                       mxser_change_speed(info, NULL);
-               }
-       } else {
-               retval = mxser_startup(info);
+       if (port->xmit_cnt < WAKEUP_CHARS)
+               tty_wakeup(port->tty);
+
+       if (port->xmit_cnt <= 0) {
+               port->IER &= ~UART_IER_THRI;
+               outb(port->IER, port->ioaddr + UART_IER);
        }
-       return retval;
 }
 
 /*
- * mxser_get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space.
+ * This is the serial driver's generic interrupt routine
  */
-static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int __user *value)
+static irqreturn_t mxser_interrupt(int irq, void *dev_id)
 {
-       unsigned char status;
-       unsigned int result;
-       unsigned long flags;
+       int status, iir, i;
+       struct mxser_board *brd = NULL;
+       struct mxser_port *port;
+       int max, irqbits, bits, msr;
+       unsigned int int_cnt, pass_counter = 0;
+       int handled = IRQ_NONE;
 
-       spin_lock_irqsave(&info->slock, flags);
-       status = inb(info->base + UART_LSR);
-       spin_unlock_irqrestore(&info->slock, flags);
-       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-       return put_user(result, value);
-}
+       for (i = 0; i < MXSER_BOARDS; i++)
+               if (dev_id == &mxser_boards[i]) {
+                       brd = dev_id;
+                       break;
+               }
 
-/*
- * This routine sends a break character out the serial port.
- */
-static void mxser_send_break(struct mxser_struct *info, int duration)
-{
-       unsigned long flags;
+       if (i == MXSER_BOARDS)
+               goto irq_stop;
+       if (brd == NULL)
+               goto irq_stop;
+       max = brd->info->nports;
+       while (pass_counter++ < MXSER_ISR_PASS_LIMIT) {
+               irqbits = inb(brd->vector) & brd->vector_mask;
+               if (irqbits == brd->vector_mask)
+                       break;
 
-       if (!info->base)
-               return;
-       set_current_state(TASK_INTERRUPTIBLE);
-       spin_lock_irqsave(&info->slock, flags);
-       outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
-               info->base + UART_LCR);
-       spin_unlock_irqrestore(&info->slock, flags);
-       schedule_timeout(duration);
-       spin_lock_irqsave(&info->slock, flags);
-       outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
-               info->base + UART_LCR);
-       spin_unlock_irqrestore(&info->slock, flags);
-}
+               handled = IRQ_HANDLED;
+               for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
+                       if (irqbits == brd->vector_mask)
+                               break;
+                       if (bits & irqbits)
+                               continue;
+                       port = &brd->ports[i];
+
+                       int_cnt = 0;
+                       spin_lock(&port->slock);
+                       do {
+                               iir = inb(port->ioaddr + UART_IIR);
+                               if (iir & UART_IIR_NO_INT)
+                                       break;
+                               iir &= MOXA_MUST_IIR_MASK;
+                               if (!port->tty ||
+                                               (port->flags & ASYNC_CLOSING) ||
+                                               !(port->flags &
+                                                       ASYNC_INITIALIZED)) {
+                                       status = inb(port->ioaddr + UART_LSR);
+                                       outb(0x27, port->ioaddr + UART_FCR);
+                                       inb(port->ioaddr + UART_MSR);
+                                       break;
+                               }
 
-static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct mxser_struct *info = tty->driver_data;
-       unsigned char control, status;
-       unsigned long flags;
+                               status = inb(port->ioaddr + UART_LSR);
+
+                               if (status & UART_LSR_PE)
+                                       port->err_shadow |= NPPI_NOTIFY_PARITY;
+                               if (status & UART_LSR_FE)
+                                       port->err_shadow |= NPPI_NOTIFY_FRAMING;
+                               if (status & UART_LSR_OE)
+                                       port->err_shadow |=
+                                               NPPI_NOTIFY_HW_OVERRUN;
+                               if (status & UART_LSR_BI)
+                                       port->err_shadow |= NPPI_NOTIFY_BREAK;
+
+                               if (port->board->chip_flag) {
+                                       if (iir == MOXA_MUST_IIR_GDA ||
+                                           iir == MOXA_MUST_IIR_RDA ||
+                                           iir == MOXA_MUST_IIR_RTO ||
+                                           iir == MOXA_MUST_IIR_LSR)
+                                               mxser_receive_chars(port,
+                                                               &status);
+
+                               } else {
+                                       status &= port->read_status_mask;
+                                       if (status & UART_LSR_DR)
+                                               mxser_receive_chars(port,
+                                                               &status);
+                               }
+                               msr = inb(port->ioaddr + UART_MSR);
+                               if (msr & UART_MSR_ANY_DELTA)
+                                       mxser_check_modem_status(port, msr);
+
+                               if (port->board->chip_flag) {
+                                       if (iir == 0x02 && (status &
+                                                               UART_LSR_THRE))
+                                               mxser_transmit_chars(port);
+                               } else {
+                                       if (status & UART_LSR_THRE)
+                                               mxser_transmit_chars(port);
+                               }
+                       } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
+                       spin_unlock(&port->slock);
+               }
+       }
 
+irq_stop:
+       return handled;
+}
 
-       if (tty->index == MXSER_PORTS)
-               return -ENOIOCTLCMD;
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
+static const struct tty_operations mxser_ops = {
+       .open = mxser_open,
+       .close = mxser_close,
+       .write = mxser_write,
+       .put_char = mxser_put_char,
+       .flush_chars = mxser_flush_chars,
+       .write_room = mxser_write_room,
+       .chars_in_buffer = mxser_chars_in_buffer,
+       .flush_buffer = mxser_flush_buffer,
+       .ioctl = mxser_ioctl,
+       .throttle = mxser_throttle,
+       .unthrottle = mxser_unthrottle,
+       .set_termios = mxser_set_termios,
+       .stop = mxser_stop,
+       .start = mxser_start,
+       .hangup = mxser_hangup,
+       .break_ctl = mxser_rs_break,
+       .wait_until_sent = mxser_wait_until_sent,
+       .tiocmget = mxser_tiocmget,
+       .tiocmset = mxser_tiocmset,
+};
 
-       control = info->MCR;
+/*
+ * The MOXA Smartio/Industio serial driver boot-time initialization code!
+ */
 
-       spin_lock_irqsave(&info->slock, flags);
-       status = inb(info->base + UART_MSR);
-       if (status & UART_MSR_ANY_DELTA)
-               mxser_check_modem_status(info, status);
-       spin_unlock_irqrestore(&info->slock, flags);
-       return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
-                   ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
-                   ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
-                   ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
-                   ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
-                   ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
+               unsigned int irq)
+{
+       if (irq)
+               free_irq(brd->irq, brd);
+       if (pdev != NULL) {     /* PCI */
+#ifdef CONFIG_PCI
+               pci_release_region(pdev, 2);
+               pci_release_region(pdev, 3);
+#endif
+       } else {
+               release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+               release_region(brd->vector, 1);
+       }
 }
 
-static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear)
+static int __devinit mxser_initbrd(struct mxser_board *brd,
+               struct pci_dev *pdev)
 {
-       struct mxser_struct *info = tty->driver_data;
-       unsigned long flags;
+       struct mxser_port *info;
+       unsigned int i;
+       int retval;
 
+       printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud);
 
-       if (tty->index == MXSER_PORTS)
-               return -ENOIOCTLCMD;
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
+       for (i = 0; i < brd->info->nports; i++) {
+               info = &brd->ports[i];
+               info->board = brd;
+               info->stop_rx = 0;
+               info->ldisc_stop_rx = 0;
 
-       spin_lock_irqsave(&info->slock, flags);
+               /* Enhance mode enabled here */
+               if (brd->chip_flag != MOXA_OTHER_UART)
+                       ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr);
 
-       if (set & TIOCM_RTS)
-               info->MCR |= UART_MCR_RTS;
-       if (set & TIOCM_DTR)
-               info->MCR |= UART_MCR_DTR;
+               info->flags = ASYNC_SHARE_IRQ;
+               info->type = brd->uart_type;
 
-       if (clear & TIOCM_RTS)
-               info->MCR &= ~UART_MCR_RTS;
-       if (clear & TIOCM_DTR)
-               info->MCR &= ~UART_MCR_DTR;
+               process_txrx_fifo(info);
 
-       outb(info->MCR, info->base + UART_MCR);
-       spin_unlock_irqrestore(&info->slock, flags);
-       return 0;
-}
+               info->custom_divisor = info->baud_base * 16;
+               info->close_delay = 5 * HZ / 10;
+               info->closing_wait = 30 * HZ;
+               info->normal_termios = mxvar_sdriver->init_termios;
+               init_waitqueue_head(&info->open_wait);
+               init_waitqueue_head(&info->delta_msr_wait);
+               memset(&info->mon_data, 0, sizeof(struct mxser_mon));
+               info->err_shadow = 0;
+               spin_lock_init(&info->slock);
 
+               /* before set INT ISR, disable all int */
+               outb(inb(info->ioaddr + UART_IER) & 0xf0,
+                       info->ioaddr + UART_IER);
+       }
 
-static int mxser_read_register(int, unsigned short *);
-static int mxser_program_mode(int);
-static void mxser_normal_mode(int);
+       retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
+                       brd);
+       if (retval) {
+               printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
+                       "conflict with another device.\n",
+                       brd->info->name, brd->irq);
+               /* We hold resources, we need to release them. */
+               mxser_release_res(brd, pdev, 0);
+       }
+       return retval;
+}
 
-static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
+static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
 {
        int id, i, bits;
        unsigned short regs[16], irq;
        unsigned char scratch, scratch2;
 
-       hwconf->IsMoxaMustChipFlag = MOXA_OTHER_UART;
+       brd->chip_flag = MOXA_OTHER_UART;
 
        id = mxser_read_register(cap, regs);
-       if (id == C168_ASIC_ID) {
-               hwconf->board_type = MXSER_BOARD_C168_ISA;
-               hwconf->ports = 8;
-       } else if (id == C104_ASIC_ID) {
-               hwconf->board_type = MXSER_BOARD_C104_ISA;
-               hwconf->ports = 4;
-       } else if (id == C102_ASIC_ID) {
-               hwconf->board_type = MXSER_BOARD_C102_ISA;
-               hwconf->ports = 2;
-       } else if (id == CI132_ASIC_ID) {
-               hwconf->board_type = MXSER_BOARD_CI132;
-               hwconf->ports = 2;
-       } else if (id == CI134_ASIC_ID) {
-               hwconf->board_type = MXSER_BOARD_CI134;
-               hwconf->ports = 4;
-       } else if (id == CI104J_ASIC_ID) {
-               hwconf->board_type = MXSER_BOARD_CI104J;
-               hwconf->ports = 4;
-       } else
+       switch (id) {
+       case C168_ASIC_ID:
+               brd->info = &mxser_cards[0];
+               break;
+       case C104_ASIC_ID:
+               brd->info = &mxser_cards[1];
+               break;
+       case CI104J_ASIC_ID:
+               brd->info = &mxser_cards[2];
+               break;
+       case C102_ASIC_ID:
+               brd->info = &mxser_cards[5];
+               break;
+       case CI132_ASIC_ID:
+               brd->info = &mxser_cards[6];
+               break;
+       case CI134_ASIC_ID:
+               brd->info = &mxser_cards[7];
+               break;
+       default:
                return 0;
+       }
 
        irq = 0;
-       if (hwconf->ports == 2) {
+       /* some ISA cards have 2 ports, but we want to see them as 4-port (why?)
+          Flag-hack checks if configuration should be read as 2-port here. */
+       if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) {
                irq = regs[9] & 0xF000;
                irq = irq | (irq >> 4);
                if (irq != (regs[9] & 0xFF00))
                        return MXSER_ERR_IRQ_CONFLIT;
-       } else if (hwconf->ports == 4) {
+       } else if (brd->info->nports == 4) {
                irq = regs[9] & 0xF000;
                irq = irq | (irq >> 4);
                irq = irq | (irq >> 8);
                if (irq != regs[9])
                        return MXSER_ERR_IRQ_CONFLIT;
-       } else if (hwconf->ports == 8) {
+       } else if (brd->info->nports == 8) {
                irq = regs[9] & 0xF000;
                irq = irq | (irq >> 4);
                irq = irq | (irq >> 8);
@@ -2984,23 +2432,23 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
 
        if (!irq)
                return MXSER_ERR_IRQ;
-       hwconf->irq = ((int)(irq & 0xF000) >> 12);
+       brd->irq = ((int)(irq & 0xF000) >> 12);
        for (i = 0; i < 8; i++)
-               hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8;
+               brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8;
        if ((regs[12] & 0x80) == 0)
                return MXSER_ERR_VECTOR;
-       hwconf->vector = (int)regs[11]; /* interrupt vector */
+       brd->vector = (int)regs[11];    /* interrupt vector */
        if (id == 1)
-               hwconf->vector_mask = 0x00FF;
+               brd->vector_mask = 0x00FF;
        else
-               hwconf->vector_mask = 0x000F;
+               brd->vector_mask = 0x000F;
        for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
                if (regs[12] & bits) {
-                       hwconf->baud_base[i] = 921600;
-                       hwconf->MaxCanSetBaudRate[i] = 921600;  /* add by Victor Yu. 09-04-2002 */
+                       brd->ports[i].baud_base = 921600;
+                       brd->ports[i].max_baud = 921600;
                } else {
-                       hwconf->baud_base[i] = 115200;
-                       hwconf->MaxCanSetBaudRate[i] = 115200;  /* add by Victor Yu. 09-04-2002 */
+                       brd->ports[i].baud_base = 115200;
+                       brd->ports[i].max_baud = 115200;
                }
        }
        scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
@@ -3011,123 +2459,279 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
        scratch = inb(cap + UART_IIR);
 
        if (scratch & 0xC0)
-               hwconf->uart_type = PORT_16550A;
+               brd->uart_type = PORT_16550A;
        else
-               hwconf->uart_type = PORT_16450;
-       if (id == 1)
-               hwconf->ports = 8;
-       else
-               hwconf->ports = 4;
-       request_region(hwconf->ioaddr[0], 8 * hwconf->ports, "mxser(IO)");
-       request_region(hwconf->vector, 1, "mxser(vector)");
-       return hwconf->ports;
+               brd->uart_type = PORT_16450;
+       if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
+                       "mxser(IO)"))
+               return MXSER_ERR_IOADDR;
+       if (!request_region(brd->vector, 1, "mxser(vector)")) {
+               release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+               return MXSER_ERR_VECTOR;
+       }
+       return brd->info->nports;
 }
 
-#define CHIP_SK        0x01    /* Serial Data Clock  in Eprom */
-#define CHIP_DO        0x02    /* Serial Data Output in Eprom */
-#define CHIP_CS        0x04    /* Serial Chip Select in Eprom */
-#define CHIP_DI        0x08    /* Serial Data Input  in Eprom */
-#define EN_CCMD        0x000   /* Chip's command register     */
-#define EN0_RSARLO     0x008   /* Remote start address reg 0  */
-#define EN0_RSARHI     0x009   /* Remote start address reg 1  */
-#define EN0_RCNTLO     0x00A   /* Remote byte count reg WR    */
-#define EN0_RCNTHI     0x00B   /* Remote byte count reg WR    */
-#define EN0_DCFG       0x00E   /* Data configuration reg WR   */
-#define EN0_PORT       0x010   /* Rcv missed frame error counter RD */
-#define ENC_PAGE0      0x000   /* Select page 0 of chip registers   */
-#define ENC_PAGE3      0x0C0   /* Select page 3 of chip registers   */
-static int mxser_read_register(int port, unsigned short *regs)
+static int __devinit mxser_probe(struct pci_dev *pdev,
+               const struct pci_device_id *ent)
 {
-       int i, k, value, id;
-       unsigned int j;
+#ifdef CONFIG_PCI
+       struct mxser_board *brd;
+       unsigned int i, j;
+       unsigned long ioaddress;
+       int retval = -EINVAL;
 
-       id = mxser_program_mode(port);
-       if (id < 0)
-               return id;
-       for (i = 0; i < 14; i++) {
-               k = (i & 0x3F) | 0x180;
-               for (j = 0x100; j > 0; j >>= 1) {
-                       outb(CHIP_CS, port);
-                       if (k & j) {
-                               outb(CHIP_CS | CHIP_DO, port);
-                               outb(CHIP_CS | CHIP_DO | CHIP_SK, port);        /* A? bit of read */
-                       } else {
-                               outb(CHIP_CS, port);
-                               outb(CHIP_CS | CHIP_SK, port);  /* A? bit of read */
+       for (i = 0; i < MXSER_BOARDS; i++)
+               if (mxser_boards[i].info == NULL)
+                       break;
+
+       if (i >= MXSER_BOARDS) {
+               printk(KERN_ERR "Too many Smartio/Industio family boards found "
+                       "(maximum %d), board not configured\n", MXSER_BOARDS);
+               goto err;
+       }
+
+       brd = &mxser_boards[i];
+       brd->idx = i * MXSER_PORTS_PER_BOARD;
+       printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
+               mxser_cards[ent->driver_data].name,
+               pdev->bus->number, PCI_SLOT(pdev->devfn));
+
+       retval = pci_enable_device(pdev);
+       if (retval) {
+               printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+               goto err;
+       }
+
+       /* io address */
+       ioaddress = pci_resource_start(pdev, 2);
+       retval = pci_request_region(pdev, 2, "mxser(IO)");
+       if (retval)
+               goto err;
+
+       brd->info = &mxser_cards[ent->driver_data];
+       for (i = 0; i < brd->info->nports; i++)
+               brd->ports[i].ioaddr = ioaddress + 8 * i;
+
+       /* vector */
+       ioaddress = pci_resource_start(pdev, 3);
+       retval = pci_request_region(pdev, 3, "mxser(vector)");
+       if (retval)
+               goto err_relio;
+       brd->vector = ioaddress;
+
+       /* irq */
+       brd->irq = pdev->irq;
+
+       brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr);
+       brd->uart_type = PORT_16550A;
+       brd->vector_mask = 0;
+
+       for (i = 0; i < brd->info->nports; i++) {
+               for (j = 0; j < UART_INFO_NUM; j++) {
+                       if (Gpci_uart_info[j].type == brd->chip_flag) {
+                               brd->ports[i].max_baud =
+                                       Gpci_uart_info[j].max_baud;
+
+                               /* exception....CP-102 */
+                               if (brd->info->flags & MXSER_HIGHBAUD)
+                                       brd->ports[i].max_baud = 921600;
+                               break;
                        }
                }
-               (void)inb(port);
-               value = 0;
-               for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
-                       outb(CHIP_CS, port);
-                       outb(CHIP_CS | CHIP_SK, port);
-                       if (inb(port) & CHIP_DI)
-                               value |= j;
+       }
+
+       if (brd->chip_flag == MOXA_MUST_MU860_HWID) {
+               for (i = 0; i < brd->info->nports; i++) {
+                       if (i < 4)
+                               brd->ports[i].opmode_ioaddr = ioaddress + 4;
+                       else
+                               brd->ports[i].opmode_ioaddr = ioaddress + 0x0c;
                }
-               regs[i] = value;
-               outb(0, port);
+               outb(0, ioaddress + 4); /* default set to RS232 mode */
+               outb(0, ioaddress + 0x0c);      /* default set to RS232 mode */
        }
-       mxser_normal_mode(port);
-       return id;
+
+       for (i = 0; i < brd->info->nports; i++) {
+               brd->vector_mask |= (1 << i);
+               brd->ports[i].baud_base = 921600;
+       }
+
+       /* mxser_initbrd will hook ISR. */
+       retval = mxser_initbrd(brd, pdev);
+       if (retval)
+               goto err_null;
+
+       for (i = 0; i < brd->info->nports; i++)
+               tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+
+       pci_set_drvdata(pdev, brd);
+
+       return 0;
+err_relio:
+       pci_release_region(pdev, 2);
+err_null:
+       brd->info = NULL;
+err:
+       return retval;
+#else
+       return -ENODEV;
+#endif
 }
 
-static int mxser_program_mode(int port)
+static void __devexit mxser_remove(struct pci_dev *pdev)
 {
-       int id, i, j, n;
-       /* unsigned long flags; */
+       struct mxser_board *brd = pci_get_drvdata(pdev);
+       unsigned int i;
 
-       spin_lock(&gm_lock);
-       outb(0, port);
-       outb(0, port);
-       outb(0, port);
-       (void)inb(port);
-       (void)inb(port);
-       outb(0, port);
-       (void)inb(port);
-       /* restore_flags(flags); */
-       spin_unlock(&gm_lock);
+       for (i = 0; i < brd->info->nports; i++)
+               tty_unregister_device(mxvar_sdriver, brd->idx + i);
 
-       id = inb(port + 1) & 0x1F;
-       if ((id != C168_ASIC_ID) &&
-                       (id != C104_ASIC_ID) &&
-                       (id != C102_ASIC_ID) &&
-                       (id != CI132_ASIC_ID) &&
-                       (id != CI134_ASIC_ID) &&
-                       (id != CI104J_ASIC_ID))
-               return -1;
-       for (i = 0, j = 0; i < 4; i++) {
-               n = inb(port + 2);
-               if (n == 'M') {
-                       j = 1;
-               } else if ((j == 1) && (n == 1)) {
-                       j = 2;
-                       break;
-               } else
-                       j = 0;
-       }
-       if (j != 2)
-               id = -2;
-       return id;
+       mxser_release_res(brd, pdev, 1);
+       brd->info = NULL;
 }
 
-static void mxser_normal_mode(int port)
+static struct pci_driver mxser_driver = {
+       .name = "mxser",
+       .id_table = mxser_pcibrds,
+       .probe = mxser_probe,
+       .remove = __devexit_p(mxser_remove)
+};
+
+static int __init mxser_module_init(void)
 {
-       int i, n;
+       struct mxser_board *brd;
+       unsigned long cap;
+       unsigned int i, m, isaloop;
+       int retval, b;
 
-       outb(0xA5, port + 1);
-       outb(0x80, port + 3);
-       outb(12, port + 0);     /* 9600 bps */
-       outb(0, port + 1);
-       outb(0x03, port + 3);   /* 8 data bits */
-       outb(0x13, port + 4);   /* loop back mode */
-       for (i = 0; i < 16; i++) {
-               n = inb(port + 5);
-               if ((n & 0x61) == 0x60)
-                       break;
-               if ((n & 1) == 1)
-                       (void)inb(port);
+       pr_debug("Loading module mxser ...\n");
+
+       mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
+       if (!mxvar_sdriver)
+               return -ENOMEM;
+
+       printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
+               MXSER_VERSION);
+
+       /* Initialize the tty_driver structure */
+       mxvar_sdriver->owner = THIS_MODULE;
+       mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
+       mxvar_sdriver->name = "ttyMI";
+       mxvar_sdriver->major = ttymajor;
+       mxvar_sdriver->minor_start = 0;
+       mxvar_sdriver->num = MXSER_PORTS + 1;
+       mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
+       mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
+       mxvar_sdriver->init_termios = tty_std_termios;
+       mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+       mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
+       tty_set_operations(mxvar_sdriver, &mxser_ops);
+
+       retval = tty_register_driver(mxvar_sdriver);
+       if (retval) {
+               printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family "
+                               "tty driver !\n");
+               goto err_put;
        }
-       outb(0x00, port + 4);
+
+       mxvar_diagflag = 0;
+
+       m = 0;
+       /* Start finding ISA boards here */
+       for (isaloop = 0; isaloop < 2; isaloop++)
+               for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+                       if (!isaloop)
+                               cap = mxserBoardCAP[b]; /* predefined */
+                       else
+                               cap = ioaddr[b]; /* module param */
+
+                       if (!cap)
+                               continue;
+
+                       brd = &mxser_boards[m];
+                       retval = mxser_get_ISA_conf(cap, brd);
+
+                       if (retval != 0)
+                               printk(KERN_INFO "Found MOXA %s board "
+                                       "(CAP=0x%x)\n",
+                                       brd->info->name, ioaddr[b]);
+
+                       if (retval <= 0) {
+                               if (retval == MXSER_ERR_IRQ)
+                                       printk(KERN_ERR "Invalid interrupt "
+                                               "number, board not "
+                                               "configured\n");
+                               else if (retval == MXSER_ERR_IRQ_CONFLIT)
+                                       printk(KERN_ERR "Invalid interrupt "
+                                               "number, board not "
+                                               "configured\n");
+                               else if (retval == MXSER_ERR_VECTOR)
+                                       printk(KERN_ERR "Invalid interrupt "
+                                               "vector, board not "
+                                               "configured\n");
+                               else if (retval == MXSER_ERR_IOADDR)
+                                       printk(KERN_ERR "Invalid I/O address, "
+                                               "board not configured\n");
+
+                               brd->info = NULL;
+                               continue;
+                       }
+
+                       /* mxser_initbrd will hook ISR. */
+                       if (mxser_initbrd(brd, NULL) < 0) {
+                               brd->info = NULL;
+                               continue;
+                       }
+
+                       brd->idx = m * MXSER_PORTS_PER_BOARD;
+                       for (i = 0; i < brd->info->nports; i++)
+                               tty_register_device(mxvar_sdriver, brd->idx + i,
+                                               NULL);
+
+                       m++;
+               }
+
+       retval = pci_register_driver(&mxser_driver);
+       if (retval) {
+               printk(KERN_ERR "Can't register pci driver\n");
+               if (!m) {
+                       retval = -ENODEV;
+                       goto err_unr;
+               } /* else: we have some ISA cards under control */
+       }
+
+       pr_debug("Done.\n");
+
+       return 0;
+err_unr:
+       tty_unregister_driver(mxvar_sdriver);
+err_put:
+       put_tty_driver(mxvar_sdriver);
+       return retval;
+}
+
+static void __exit mxser_module_exit(void)
+{
+       unsigned int i, j;
+
+       pr_debug("Unloading module mxser ...\n");
+
+       pci_unregister_driver(&mxser_driver);
+
+       for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
+               if (mxser_boards[i].info != NULL)
+                       for (j = 0; j < mxser_boards[i].info->nports; j++)
+                               tty_unregister_device(mxvar_sdriver,
+                                               mxser_boards[i].idx + j);
+       tty_unregister_driver(mxvar_sdriver);
+       put_tty_driver(mxvar_sdriver);
+
+       for (i = 0; i < MXSER_BOARDS; i++)
+               if (mxser_boards[i].info != NULL)
+                       mxser_release_res(&mxser_boards[i], NULL, 1);
+
+       pr_debug("Done.\n");
 }
 
 module_init(mxser_module_init);
index 1f4aa45ec004436aac1e80b03eb46dac02876741..844171115954701dd6055fd6d5be9906843486fb 100644 (file)
@@ -4,19 +4,17 @@
 /*
  *     Semi-public control interfaces
  */
+
 /*
  *     MOXA ioctls
  */
 
 #define MOXA                   0x400
 #define MOXA_GETDATACOUNT      (MOXA + 23)
-#define        MOXA_GET_CONF           (MOXA + 35)
 #define MOXA_DIAGNOSE          (MOXA + 50)
 #define MOXA_CHKPORTENABLE     (MOXA + 60)
 #define MOXA_HighSpeedOn       (MOXA + 61)
 #define MOXA_GET_MAJOR         (MOXA + 63)
-#define MOXA_GET_CUMAJOR       (MOXA + 64)
 #define MOXA_GETMSTATUS                (MOXA + 65)
 #define MOXA_SET_OP_MODE       (MOXA + 66)
 #define MOXA_GET_OP_MODE       (MOXA + 67)
 #define RS422_MODE             2
 #define RS485_4WIRE_MODE       3
 #define OP_MODE_MASK           3
-// above add by Victor Yu. 01-05-2004
-
-#define TTY_THRESHOLD_THROTTLE  128
-
-#define HI_WATER               768
-
-// added by James. 03-11-2004.
-#define MOXA_SDS_GETICOUNTER   (MOXA + 68)
-#define MOXA_SDS_RSTICOUNTER   (MOXA + 69)
-// (above) added by James.
 
+#define MOXA_SDS_RSTICOUNTER   (MOXA + 69)
 #define MOXA_ASPP_OQUEUE       (MOXA + 70)
-#define MOXA_ASPP_SETBAUD      (MOXA + 71)
-#define MOXA_ASPP_GETBAUD      (MOXA + 72)
 #define MOXA_ASPP_MON          (MOXA + 73)
 #define MOXA_ASPP_LSTATUS      (MOXA + 74)
 #define MOXA_ASPP_MON_EXT      (MOXA + 75)
 #define MOXA_SET_BAUD_METHOD   (MOXA + 76)
 
-
 /* --------------------------------------------------- */
 
 #define NPPI_NOTIFY_PARITY     0x01
 #define NPPI_NOTIFY_SW_OVERRUN 0x08
 #define NPPI_NOTIFY_BREAK      0x10
 
-#define NPPI_NOTIFY_CTSHOLD         0x01       // Tx hold by CTS low
-#define NPPI_NOTIFY_DSRHOLD         0x02       // Tx hold by DSR low
-#define NPPI_NOTIFY_XOFFHOLD        0x08       // Tx hold by Xoff received
-#define NPPI_NOTIFY_XOFFXENT        0x10       // Xoff Sent
-
-//CheckIsMoxaMust return value
-#define MOXA_OTHER_UART                        0x00
-#define MOXA_MUST_MU150_HWID           0x01
-#define MOXA_MUST_MU860_HWID           0x02
-
-// follow just for Moxa Must chip define.
-//
-// when LCR register (offset 0x03) write following value,
-// the Must chip will enter enchance mode. And write value
-// on EFR (offset 0x02) bit 6,7 to change bank.
+#define NPPI_NOTIFY_CTSHOLD         0x01       /* Tx hold by CTS low */
+#define NPPI_NOTIFY_DSRHOLD         0x02       /* Tx hold by DSR low */
+#define NPPI_NOTIFY_XOFFHOLD        0x08       /* Tx hold by Xoff received */
+#define NPPI_NOTIFY_XOFFXENT        0x10       /* Xoff Sent */
+
+/* follow just for Moxa Must chip define. */
+/* */
+/* when LCR register (offset 0x03) write following value, */
+/* the Must chip will enter enchance mode. And write value */
+/* on EFR (offset 0x02) bit 6,7 to change bank. */
 #define MOXA_MUST_ENTER_ENCHANCE       0xBF
 
-// when enhance mode enable, access on general bank register
+/* when enhance mode enable, access on general bank register */
 #define MOXA_MUST_GDL_REGISTER         0x07
 #define MOXA_MUST_GDL_MASK             0x7F
 #define MOXA_MUST_GDL_HAS_BAD_DATA     0x80
 
-#define MOXA_MUST_LSR_RERR             0x80    // error in receive FIFO
-// enchance register bank select and enchance mode setting register
-// when LCR register equal to 0xBF
+#define MOXA_MUST_LSR_RERR             0x80    /* error in receive FIFO */
+/* enchance register bank select and enchance mode setting register */
+/* when LCR register equal to 0xBF */
 #define MOXA_MUST_EFR_REGISTER         0x02
-// enchance mode enable
+/* enchance mode enable */
 #define MOXA_MUST_EFR_EFRB_ENABLE      0x10
-// enchance reister bank set 0, 1, 2
+/* enchance reister bank set 0, 1, 2 */
 #define MOXA_MUST_EFR_BANK0            0x00
 #define MOXA_MUST_EFR_BANK1            0x40
 #define MOXA_MUST_EFR_BANK2            0x80
 #define MOXA_MUST_EFR_BANK3            0xC0
 #define MOXA_MUST_EFR_BANK_MASK                0xC0
 
-// set XON1 value register, when LCR=0xBF and change to bank0
+/* set XON1 value register, when LCR=0xBF and change to bank0 */
 #define MOXA_MUST_XON1_REGISTER                0x04
 
-// set XON2 value register, when LCR=0xBF and change to bank0
+/* set XON2 value register, when LCR=0xBF and change to bank0 */
 #define MOXA_MUST_XON2_REGISTER                0x05
 
-// set XOFF1 value register, when LCR=0xBF and change to bank0
+/* set XOFF1 value register, when LCR=0xBF and change to bank0 */
 #define MOXA_MUST_XOFF1_REGISTER       0x06
 
-// set XOFF2 value register, when LCR=0xBF and change to bank0
+/* set XOFF2 value register, when LCR=0xBF and change to bank0 */
 #define MOXA_MUST_XOFF2_REGISTER       0x07
 
 #define MOXA_MUST_RBRTL_REGISTER       0x04
 #define MOXA_MUST_ECR_REGISTER         0x06
 #define MOXA_MUST_CSR_REGISTER         0x07
 
-// good data mode enable
+/* good data mode enable */
 #define MOXA_MUST_FCR_GDA_MODE_ENABLE  0x20
-// only good data put into RxFIFO
+/* only good data put into RxFIFO */
 #define MOXA_MUST_FCR_GDA_ONLY_ENABLE  0x10
 
-// enable CTS interrupt
+/* enable CTS interrupt */
 #define MOXA_MUST_IER_ECTSI            0x80
-// enable RTS interrupt
+/* enable RTS interrupt */
 #define MOXA_MUST_IER_ERTSI            0x40
-// enable Xon/Xoff interrupt
+/* enable Xon/Xoff interrupt */
 #define MOXA_MUST_IER_XINT             0x20
-// enable GDA interrupt
+/* enable GDA interrupt */
 #define MOXA_MUST_IER_EGDAI            0x10
 
 #define MOXA_MUST_RECV_ISR             (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
 
-// GDA interrupt pending
+/* GDA interrupt pending */
 #define MOXA_MUST_IIR_GDA              0x1C
 #define MOXA_MUST_IIR_RDA              0x04
 #define MOXA_MUST_IIR_RTO              0x0C
 #define MOXA_MUST_IIR_LSR              0x06
 
-// recieved Xon/Xoff or specical interrupt pending
+/* recieved Xon/Xoff or specical interrupt pending */
 #define MOXA_MUST_IIR_XSC              0x10
 
-// RTS/CTS change state interrupt pending
+/* RTS/CTS change state interrupt pending */
 #define MOXA_MUST_IIR_RTSCTS           0x20
 #define MOXA_MUST_IIR_MASK             0x3E
 
 #define MOXA_MUST_MCR_XON_ANY          0x80
 #define MOXA_MUST_MCR_TX_XON           0x08
 
-
-// software flow control on chip mask value
+/* software flow control on chip mask value */
 #define MOXA_MUST_EFR_SF_MASK          0x0F
-// send Xon1/Xoff1
+/* send Xon1/Xoff1 */
 #define MOXA_MUST_EFR_SF_TX1           0x08
-// send Xon2/Xoff2
+/* send Xon2/Xoff2 */
 #define MOXA_MUST_EFR_SF_TX2           0x04
-// send Xon1,Xon2/Xoff1,Xoff2
+/* send Xon1,Xon2/Xoff1,Xoff2 */
 #define MOXA_MUST_EFR_SF_TX12          0x0C
-// don't send Xon/Xoff
+/* don't send Xon/Xoff */
 #define MOXA_MUST_EFR_SF_TX_NO         0x00
-// Tx software flow control mask
+/* Tx software flow control mask */
 #define MOXA_MUST_EFR_SF_TX_MASK       0x0C
-// don't receive Xon/Xoff
+/* don't receive Xon/Xoff */
 #define MOXA_MUST_EFR_SF_RX_NO         0x00
-// receive Xon1/Xoff1
+/* receive Xon1/Xoff1 */
 #define MOXA_MUST_EFR_SF_RX1           0x02
-// receive Xon2/Xoff2
+/* receive Xon2/Xoff2 */
 #define MOXA_MUST_EFR_SF_RX2           0x01
-// receive Xon1,Xon2/Xoff1,Xoff2
+/* receive Xon1,Xon2/Xoff1,Xoff2 */
 #define MOXA_MUST_EFR_SF_RX12          0x03
-// Rx software flow control mask
+/* Rx software flow control mask */
 #define MOXA_MUST_EFR_SF_RX_MASK       0x03
 
-//#define MOXA_MUST_MIN_XOFFLIMIT               66
-//#define MOXA_MUST_MIN_XONLIMIT                20
-//#define ID1_RX_TRIG                   120
-
-
-#define CHECK_MOXA_MUST_XOFFLIMIT(info) {      \
-       if ( (info)->IsMoxaMustChipFlag &&      \
-        (info)->HandFlow.XoffLimit < MOXA_MUST_MIN_XOFFLIMIT ) {       \
-               (info)->HandFlow.XoffLimit = MOXA_MUST_MIN_XOFFLIMIT;   \
-               (info)->HandFlow.XonLimit = MOXA_MUST_MIN_XONLIMIT;     \
-       }       \
-}
-
-#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do {            \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr |= MOXA_MUST_EFR_EFRB_ENABLE;     \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) {      \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr |= MOXA_MUST_EFR_EFRB_ENABLE;                     \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
+
+#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do {           \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE;    \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) {      \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE;                    \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
+
+#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) do {           \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK0;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
+       __efr |= MOXA_MUST_EFR_BANK0;                           \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
        outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER);    \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
 
-#define SET_MOXA_MUST_XON2_VALUE(baseio, Value) {      \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) do {          \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK0;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb((u8)(Value), (baseio)+MOXA_MUST_XON2_REGISTER);    \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) {     \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK0;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
+       __efr |= MOXA_MUST_EFR_BANK0;                           \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
        outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_XOFF2_VALUE(baseio, Value) {     \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK0;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb((u8)(Value), (baseio)+MOXA_MUST_XOFF2_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_RBRTL_VALUE(baseio, Value) {     \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK1;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb((u8)(Value), (baseio)+MOXA_MUST_RBRTL_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_RBRTH_VALUE(baseio, Value) {     \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK1;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb((u8)(Value), (baseio)+MOXA_MUST_RBRTH_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_RBRTI_VALUE(baseio, Value) {     \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
+
+#define SET_MOXA_MUST_FIFO_VALUE(info) do {                    \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((info)->ioaddr+UART_LCR);                \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR);\
+       __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER);     \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
+       __efr |= MOXA_MUST_EFR_BANK1;                           \
+       outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER);     \
+       outb((u8)((info)->rx_high_water), (info)->ioaddr+       \
+                       MOXA_MUST_RBRTH_REGISTER);              \
+       outb((u8)((info)->rx_trigger), (info)->ioaddr+          \
+                       MOXA_MUST_RBRTI_REGISTER);              \
+       outb((u8)((info)->rx_low_water), (info)->ioaddr+        \
+                       MOXA_MUST_RBRTL_REGISTER);              \
+       outb(__oldlcr, (info)->ioaddr+UART_LCR);                \
+} while (0)
+
+#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do {           \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK1;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb((u8)(Value), (baseio)+MOXA_MUST_RBRTI_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_THRTL_VALUE(baseio, Value) {     \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK1;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb((u8)(Value), (baseio)+MOXA_MUST_THRTL_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-//#define MOXA_MUST_RBRL_VALUE  4
-#define SET_MOXA_MUST_FIFO_VALUE(info) {       \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((info)->base+UART_LCR);  \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (info)->base+UART_LCR);  \
-       __efr = inb((info)->base+MOXA_MUST_EFR_REGISTER);       \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK1;   \
-       outb(__efr, (info)->base+MOXA_MUST_EFR_REGISTER);       \
-       outb((u8)((info)->rx_high_water), (info)->base+MOXA_MUST_RBRTH_REGISTER);       \
-       outb((u8)((info)->rx_trigger), (info)->base+MOXA_MUST_RBRTI_REGISTER);  \
-       outb((u8)((info)->rx_low_water), (info)->base+MOXA_MUST_RBRTL_REGISTER);        \
-       outb(__oldlcr, (info)->base+UART_LCR);  \
-}
-
-
-
-#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) {      \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK2;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
+       __efr |= MOXA_MUST_EFR_BANK2;                           \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
        outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER);    \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
 
-#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) {       \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
-       __efr |= MOXA_MUST_EFR_BANK2;   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) {       \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_SF_MASK;        \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_JUST_TX_SOFTWARE_FLOW_CONTROL(baseio) {  \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_SF_MASK;        \
-       __efr |= MOXA_MUST_EFR_SF_TX1;  \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) {    \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do {            \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_SF_TX_MASK;     \
-       __efr |= MOXA_MUST_EFR_SF_TX1;  \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) {   \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
+       __efr |= MOXA_MUST_EFR_BANK2;                           \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
+       *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER);           \
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
+
+#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) do {    \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_SF_TX_MASK;     \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define SET_MOXA_MUST_JUST_RX_SOFTWARE_FLOW_CONTROL(baseio) {  \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_SF_MASK;                        \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
+
+#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_SF_MASK;        \
-       __efr |= MOXA_MUST_EFR_SF_RX1;  \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) {    \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_SF_TX_MASK;                     \
+       __efr |= MOXA_MUST_EFR_SF_TX1;                          \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
+
+#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do {        \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_SF_RX_MASK;     \
-       __efr |= MOXA_MUST_EFR_SF_RX1;  \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) {   \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_SF_TX_MASK;                     \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
+
+#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_SF_RX_MASK;     \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define ENABLE_MOXA_MUST_TX_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
-       u8      __oldlcr, __efr;        \
-       __oldlcr = inb((baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_SF_RX_MASK;                     \
+       __efr |= MOXA_MUST_EFR_SF_RX1;                          \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
+
+#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do {        \
+       u8      __oldlcr, __efr;                                \
+       __oldlcr = inb((baseio)+UART_LCR);                      \
        outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
-       __efr &= ~MOXA_MUST_EFR_SF_MASK;        \
-       __efr |= (MOXA_MUST_EFR_SF_RX1|MOXA_MUST_EFR_SF_TX1);   \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);      \
-}
-
-#define ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) {        \
-       u8      __oldmcr;       \
-       __oldmcr = inb((baseio)+UART_MCR);      \
-       __oldmcr |= MOXA_MUST_MCR_XON_ANY;      \
-       outb(__oldmcr, (baseio)+UART_MCR);      \
-}
-
-#define DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) {       \
-       u8      __oldmcr;       \
-       __oldmcr = inb((baseio)+UART_MCR);      \
-       __oldmcr &= ~MOXA_MUST_MCR_XON_ANY;     \
-       outb(__oldmcr, (baseio)+UART_MCR);      \
-}
-
-#define READ_MOXA_MUST_GDL(baseio)     inb((baseio)+MOXA_MUST_GDL_REGISTER)
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
+       __efr &= ~MOXA_MUST_EFR_SF_RX_MASK;                     \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
+       outb(__oldlcr, (baseio)+UART_LCR);                      \
+} while (0)
 
 #endif
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
deleted file mode 100644 (file)
index 081c84c..0000000
+++ /dev/null
@@ -1,2817 +0,0 @@
-/*
- *          mxser.c  -- MOXA Smartio/Industio family multiport serial driver.
- *
- *      Copyright (C) 1999-2006  Moxa Technologies (support@moxa.com.tw).
- *     Copyright (C) 2006-2007  Jiri Slaby <jirislaby@gmail.com>
- *
- *      This code is loosely based on the 1.8 moxa driver which is based on
- *     Linux serial driver, written by Linus Torvalds, Theodore T'so and
- *     others.
- *
- *      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.
- *
- *     Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
- *     <alan@redhat.com>. The original 1.8 code is available on www.moxa.com.
- *     - Fixed x86_64 cleanness
- *     - Fixed sleep with spinlock held in mxser_send_break
- */
-
-#include <linux/module.h>
-#include <linux/autoconf.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/gfp.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "mxser_new.h"
-
-#define        MXSER_VERSION   "2.0.2"         /* 1.10 */
-#define        MXSERMAJOR       174
-#define        MXSERCUMAJOR     175
-
-#define MXSER_BOARDS           4       /* Max. boards */
-#define MXSER_PORTS_PER_BOARD  8       /* Max. ports per board */
-#define MXSER_PORTS            (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
-#define MXSER_ISR_PASS_LIMIT   100
-
-#define        MXSER_ERR_IOADDR        -1
-#define        MXSER_ERR_IRQ           -2
-#define        MXSER_ERR_IRQ_CONFLIT   -3
-#define        MXSER_ERR_VECTOR        -4
-
-/*CheckIsMoxaMust return value*/
-#define MOXA_OTHER_UART                0x00
-#define MOXA_MUST_MU150_HWID   0x01
-#define MOXA_MUST_MU860_HWID   0x02
-
-#define WAKEUP_CHARS           256
-
-#define UART_MCR_AFE           0x20
-#define UART_LSR_SPECIAL       0x1E
-
-#define PCI_DEVICE_ID_CB108    0x1080
-#define PCI_DEVICE_ID_CB114    0x1142
-#define PCI_DEVICE_ID_CB134I   0x1341
-#define PCI_DEVICE_ID_CP138U   0x1380
-#define PCI_DEVICE_ID_POS104UL 0x1044
-
-
-#define C168_ASIC_ID    1
-#define C104_ASIC_ID    2
-#define C102_ASIC_ID   0xB
-#define CI132_ASIC_ID  4
-#define CI134_ASIC_ID  3
-#define CI104J_ASIC_ID  5
-
-#define MXSER_HIGHBAUD 1
-#define MXSER_HAS2     2
-
-/* This is only for PCI */
-static const struct {
-       int type;
-       int tx_fifo;
-       int rx_fifo;
-       int xmit_fifo_size;
-       int rx_high_water;
-       int rx_trigger;
-       int rx_low_water;
-       long max_baud;
-} Gpci_uart_info[] = {
-       {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
-       {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
-       {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
-};
-#define UART_INFO_NUM  ARRAY_SIZE(Gpci_uart_info)
-
-struct mxser_cardinfo {
-       unsigned int nports;
-       char *name;
-       unsigned int flags;
-};
-
-static const struct mxser_cardinfo mxser_cards[] = {
-/* 0*/ { 8, "C168 series", },
-       { 4, "C104 series", },
-       { 4, "CI-104J series", },
-       { 8, "C168H/PCI series", },
-       { 4, "C104H/PCI series", },
-/* 5*/ { 4, "C102 series", MXSER_HAS2 },       /* C102-ISA */
-       { 4, "CI-132 series", MXSER_HAS2 },
-       { 4, "CI-134 series", },
-       { 2, "CP-132 series", },
-       { 4, "CP-114 series", },
-/*10*/ { 4, "CT-114 series", },
-       { 2, "CP-102 series", MXSER_HIGHBAUD },
-       { 4, "CP-104U series", },
-       { 8, "CP-168U series", },
-       { 2, "CP-132U series", },
-/*15*/ { 4, "CP-134U series", },
-       { 4, "CP-104JU series", },
-       { 8, "Moxa UC7000 Serial", },           /* RC7000 */
-       { 8, "CP-118U series", },
-       { 2, "CP-102UL series", },
-/*20*/ { 2, "CP-102U series", },
-       { 8, "CP-118EL series", },
-       { 8, "CP-168EL series", },
-       { 4, "CP-104EL series", },
-       { 8, "CB-108 series", },
-/*25*/ { 4, "CB-114 series", },
-       { 4, "CB-134I series", },
-       { 8, "CP-138U series", },
-       { 4, "POS-104UL series", }
-};
-
-/* driver_data correspond to the lines in the structure above
-   see also ISA probe function before you change something */
-static struct pci_device_id mxser_pcibrds[] = {
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168),   .driver_data = 3 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104),   .driver_data = 4 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132),  .driver_data = 8 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114),  .driver_data = 9 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114),  .driver_data = 10 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102),  .driver_data = 11 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108),       .driver_data = 24 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114),       .driver_data = 25 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I),      .driver_data = 26 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U),      .driver_data = 27 },
-       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL),    .driver_data = 28 },
-       { }
-};
-MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
-
-static int mxvar_baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
-       4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
-};
-static unsigned int mxvar_baud_table1[] = {
-       0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400,
-       B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600
-};
-#define BAUD_TABLE_NO ARRAY_SIZE(mxvar_baud_table)
-
-#define B_SPEC B2000000
-
-static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
-static int ttymajor = MXSERMAJOR;
-static int calloutmajor = MXSERCUMAJOR;
-
-/* Variables for insmod */
-
-MODULE_AUTHOR("Casper Yang");
-MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
-module_param_array(ioaddr, int, NULL, 0);
-module_param(ttymajor, int, 0);
-MODULE_LICENSE("GPL");
-
-struct mxser_log {
-       int tick;
-       unsigned long rxcnt[MXSER_PORTS];
-       unsigned long txcnt[MXSER_PORTS];
-};
-
-
-struct mxser_mon {
-       unsigned long rxcnt;
-       unsigned long txcnt;
-       unsigned long up_rxcnt;
-       unsigned long up_txcnt;
-       int modem_status;
-       unsigned char hold_reason;
-};
-
-struct mxser_mon_ext {
-       unsigned long rx_cnt[32];
-       unsigned long tx_cnt[32];
-       unsigned long up_rxcnt[32];
-       unsigned long up_txcnt[32];
-       int modem_status[32];
-
-       long baudrate[32];
-       int databits[32];
-       int stopbits[32];
-       int parity[32];
-       int flowctrl[32];
-       int fifo[32];
-       int iftype[32];
-};
-
-struct mxser_board;
-
-struct mxser_port {
-       struct mxser_board *board;
-       struct tty_struct *tty;
-
-       unsigned long ioaddr;
-       unsigned long opmode_ioaddr;
-       int max_baud;
-
-       int rx_high_water;
-       int rx_trigger;         /* Rx fifo trigger level */
-       int rx_low_water;
-       int baud_base;          /* max. speed */
-       long realbaud;
-       int type;               /* UART type */
-       int flags;              /* defined in tty.h */
-       int speed;
-
-       int x_char;             /* xon/xoff character */
-       int IER;                /* Interrupt Enable Register */
-       int MCR;                /* Modem control register */
-
-       unsigned char stop_rx;
-       unsigned char ldisc_stop_rx;
-
-       int custom_divisor;
-       int close_delay;
-       unsigned short closing_wait;
-       unsigned char err_shadow;
-       unsigned long event;
-
-       int count;              /* # of fd on device */
-       int blocked_open;       /* # of blocked opens */
-       struct async_icount icount; /* kernel counters for 4 input interrupts */
-       int timeout;
-
-       int read_status_mask;
-       int ignore_status_mask;
-       int xmit_fifo_size;
-       unsigned char *xmit_buf;
-       int xmit_head;
-       int xmit_tail;
-       int xmit_cnt;
-
-       struct ktermios normal_termios;
-
-       struct mxser_mon mon_data;
-
-       spinlock_t slock;
-       wait_queue_head_t open_wait;
-       wait_queue_head_t delta_msr_wait;
-};
-
-struct mxser_board {
-       unsigned int idx;
-       int irq;
-       const struct mxser_cardinfo *info;
-       unsigned long vector;
-       unsigned long vector_mask;
-
-       int chip_flag;
-       int uart_type;
-
-       struct mxser_port ports[MXSER_PORTS_PER_BOARD];
-};
-
-struct mxser_mstatus {
-       tcflag_t cflag;
-       int cts;
-       int dsr;
-       int ri;
-       int dcd;
-};
-
-static struct mxser_mstatus GMStatus[MXSER_PORTS];
-
-static int mxserBoardCAP[MXSER_BOARDS] = {
-       0, 0, 0, 0
-       /*  0x180, 0x280, 0x200, 0x320 */
-};
-
-static struct mxser_board mxser_boards[MXSER_BOARDS];
-static struct tty_driver *mxvar_sdriver;
-static struct mxser_log mxvar_log;
-static int mxvar_diagflag;
-static unsigned char mxser_msr[MXSER_PORTS + 1];
-static struct mxser_mon_ext mon_data_ext;
-static int mxser_set_baud_method[MXSER_PORTS + 1];
-
-#ifdef CONFIG_PCI
-static int __devinit CheckIsMoxaMust(int io)
-{
-       u8 oldmcr, hwid;
-       int i;
-
-       outb(0, io + UART_LCR);
-       DISABLE_MOXA_MUST_ENCHANCE_MODE(io);
-       oldmcr = inb(io + UART_MCR);
-       outb(0, io + UART_MCR);
-       SET_MOXA_MUST_XON1_VALUE(io, 0x11);
-       if ((hwid = inb(io + UART_MCR)) != 0) {
-               outb(oldmcr, io + UART_MCR);
-               return MOXA_OTHER_UART;
-       }
-
-       GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
-       for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
-               if (hwid == Gpci_uart_info[i].type)
-                       return (int)hwid;
-       }
-       return MOXA_OTHER_UART;
-}
-#endif
-
-static void process_txrx_fifo(struct mxser_port *info)
-{
-       int i;
-
-       if ((info->type == PORT_16450) || (info->type == PORT_8250)) {
-               info->rx_trigger = 1;
-               info->rx_high_water = 1;
-               info->rx_low_water = 1;
-               info->xmit_fifo_size = 1;
-       } else
-               for (i = 0; i < UART_INFO_NUM; i++)
-                       if (info->board->chip_flag == Gpci_uart_info[i].type) {
-                               info->rx_trigger = Gpci_uart_info[i].rx_trigger;
-                               info->rx_low_water = Gpci_uart_info[i].rx_low_water;
-                               info->rx_high_water = Gpci_uart_info[i].rx_high_water;
-                               info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size;
-                               break;
-                       }
-}
-
-static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
-{
-       unsigned char status = 0;
-
-       status = inb(baseaddr + UART_MSR);
-
-       mxser_msr[port] &= 0x0F;
-       mxser_msr[port] |= status;
-       status = mxser_msr[port];
-       if (mode)
-               mxser_msr[port] = 0;
-
-       return status;
-}
-
-static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
-               struct mxser_port *port)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int retval;
-       int do_clocal = 0;
-       unsigned long flags;
-
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-                       test_bit(TTY_IO_ERROR, &tty->flags)) {
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, port->count is dropped by one, so that
-        * mxser_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&port->open_wait, &wait);
-
-       spin_lock_irqsave(&port->slock, flags);
-       if (!tty_hung_up_p(filp))
-               port->count--;
-       spin_unlock_irqrestore(&port->slock, flags);
-       port->blocked_open++;
-       while (1) {
-               spin_lock_irqsave(&port->slock, flags);
-               outb(inb(port->ioaddr + UART_MCR) |
-                       UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
-               spin_unlock_irqrestore(&port->slock, flags);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
-                       if (port->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               if (!(port->flags & ASYNC_CLOSING) &&
-                               (do_clocal ||
-                               (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&port->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               port->count++;
-       port->blocked_open--;
-       if (retval)
-               return retval;
-       port->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}
-
-static int mxser_set_baud(struct mxser_port *info, long newspd)
-{
-       unsigned int i;
-       int quot = 0;
-       unsigned char cval;
-       int ret = 0;
-
-       if (!info->tty || !info->tty->termios)
-               return ret;
-
-       if (!(info->ioaddr))
-               return ret;
-
-       if (newspd > info->max_baud)
-               return 0;
-
-       info->realbaud = newspd;
-       for (i = 0; i < BAUD_TABLE_NO; i++)
-              if (newspd == mxvar_baud_table[i])
-                      break;
-       if (i == BAUD_TABLE_NO) {
-               quot = info->baud_base / info->speed;
-               if (info->speed <= 0 || info->speed > info->max_baud)
-                       quot = 0;
-       } else {
-               if (newspd == 134) {
-                       quot = (2 * info->baud_base / 269);
-               } else if (newspd) {
-                       quot = info->baud_base / newspd;
-                       if (quot == 0)
-                               quot = 1;
-               } else {
-                       quot = 0;
-               }
-       }
-
-       info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
-       info->timeout += HZ / 50;       /* Add .02 seconds of slop */
-
-       if (quot) {
-               info->MCR |= UART_MCR_DTR;
-               outb(info->MCR, info->ioaddr + UART_MCR);
-       } else {
-               info->MCR &= ~UART_MCR_DTR;
-               outb(info->MCR, info->ioaddr + UART_MCR);
-               return ret;
-       }
-
-       cval = inb(info->ioaddr + UART_LCR);
-
-       outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR);    /* set DLAB */
-
-       outb(quot & 0xff, info->ioaddr + UART_DLL);     /* LS of divisor */
-       outb(quot >> 8, info->ioaddr + UART_DLM);       /* MS of divisor */
-       outb(cval, info->ioaddr + UART_LCR);    /* reset DLAB */
-
-       if (i == BAUD_TABLE_NO) {
-               quot = info->baud_base % info->speed;
-               quot *= 8;
-               if ((quot % info->speed) > (info->speed / 2)) {
-                       quot /= info->speed;
-                       quot++;
-               } else {
-                       quot /= info->speed;
-               }
-               SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot);
-       } else
-               SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0);
-
-       return ret;
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static int mxser_change_speed(struct mxser_port *info,
-               struct ktermios *old_termios)
-{
-       unsigned cflag, cval, fcr;
-       int ret = 0;
-       unsigned char status;
-       long baud;
-
-       if (!info->tty || !info->tty->termios)
-               return ret;
-       cflag = info->tty->termios->c_cflag;
-       if (!(info->ioaddr))
-               return ret;
-
-       if (mxser_set_baud_method[info->tty->index] == 0) {
-               if ((cflag & CBAUD) == B_SPEC)
-                       baud = info->speed;
-               else
-                       baud = tty_get_baud_rate(info->tty);
-               mxser_set_baud(info, baud);
-       }
-
-       /* byte size and parity */
-       switch (cflag & CSIZE) {
-       case CS5:
-               cval = 0x00;
-               break;
-       case CS6:
-               cval = 0x01;
-               break;
-       case CS7:
-               cval = 0x02;
-               break;
-       case CS8:
-               cval = 0x03;
-               break;
-       default:
-               cval = 0x00;
-               break;          /* too keep GCC shut... */
-       }
-       if (cflag & CSTOPB)
-               cval |= 0x04;
-       if (cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-       if (cflag & CMSPAR)
-               cval |= UART_LCR_SPAR;
-
-       if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
-               if (info->board->chip_flag) {
-                       fcr = UART_FCR_ENABLE_FIFO;
-                       fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
-                       SET_MOXA_MUST_FIFO_VALUE(info);
-               } else
-                       fcr = 0;
-       } else {
-               fcr = UART_FCR_ENABLE_FIFO;
-               if (info->board->chip_flag) {
-                       fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
-                       SET_MOXA_MUST_FIFO_VALUE(info);
-               } else {
-                       switch (info->rx_trigger) {
-                       case 1:
-                               fcr |= UART_FCR_TRIGGER_1;
-                               break;
-                       case 4:
-                               fcr |= UART_FCR_TRIGGER_4;
-                               break;
-                       case 8:
-                               fcr |= UART_FCR_TRIGGER_8;
-                               break;
-                       default:
-                               fcr |= UART_FCR_TRIGGER_14;
-                               break;
-                       }
-               }
-       }
-
-       /* CTS flow control flag and modem status interrupts */
-       info->IER &= ~UART_IER_MSI;
-       info->MCR &= ~UART_MCR_AFE;
-       if (cflag & CRTSCTS) {
-               info->flags |= ASYNC_CTS_FLOW;
-               info->IER |= UART_IER_MSI;
-               if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
-                       info->MCR |= UART_MCR_AFE;
-               } else {
-                       status = inb(info->ioaddr + UART_MSR);
-                       if (info->tty->hw_stopped) {
-                               if (status & UART_MSR_CTS) {
-                                       info->tty->hw_stopped = 0;
-                                       if (info->type != PORT_16550A &&
-                                                       !info->board->chip_flag) {
-                                               outb(info->IER & ~UART_IER_THRI,
-                                                       info->ioaddr +
-                                                       UART_IER);
-                                               info->IER |= UART_IER_THRI;
-                                               outb(info->IER, info->ioaddr +
-                                                               UART_IER);
-                                       }
-                                       tty_wakeup(info->tty);
-                               }
-                       } else {
-                               if (!(status & UART_MSR_CTS)) {
-                                       info->tty->hw_stopped = 1;
-                                       if ((info->type != PORT_16550A) &&
-                                                       (!info->board->chip_flag)) {
-                                               info->IER &= ~UART_IER_THRI;
-                                               outb(info->IER, info->ioaddr +
-                                                               UART_IER);
-                                       }
-                               }
-                       }
-               }
-       } else {
-               info->flags &= ~ASYNC_CTS_FLOW;
-       }
-       outb(info->MCR, info->ioaddr + UART_MCR);
-       if (cflag & CLOCAL) {
-               info->flags &= ~ASYNC_CHECK_CD;
-       } else {
-               info->flags |= ASYNC_CHECK_CD;
-               info->IER |= UART_IER_MSI;
-       }
-       outb(info->IER, info->ioaddr + UART_IER);
-
-       /*
-        * Set up parity check flag
-        */
-       info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (I_INPCK(info->tty))
-               info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
-               info->read_status_mask |= UART_LSR_BI;
-
-       info->ignore_status_mask = 0;
-
-       if (I_IGNBRK(info->tty)) {
-               info->ignore_status_mask |= UART_LSR_BI;
-               info->read_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignore parity and break indicators, ignore
-                * overruns too.  (For real raw support).
-                */
-               if (I_IGNPAR(info->tty)) {
-                       info->ignore_status_mask |=
-                                               UART_LSR_OE |
-                                               UART_LSR_PE |
-                                               UART_LSR_FE;
-                       info->read_status_mask |=
-                                               UART_LSR_OE |
-                                               UART_LSR_PE |
-                                               UART_LSR_FE;
-               }
-       }
-       if (info->board->chip_flag) {
-               SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
-               SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
-               if (I_IXON(info->tty)) {
-                       ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
-               } else {
-                       DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
-               }
-               if (I_IXOFF(info->tty)) {
-                       ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
-               } else {
-                       DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
-               }
-       }
-
-
-       outb(fcr, info->ioaddr + UART_FCR);     /* set fcr */
-       outb(cval, info->ioaddr + UART_LCR);
-
-       return ret;
-}
-
-static void mxser_check_modem_status(struct mxser_port *port, int status)
-{
-       /* update input line counters */
-       if (status & UART_MSR_TERI)
-               port->icount.rng++;
-       if (status & UART_MSR_DDSR)
-               port->icount.dsr++;
-       if (status & UART_MSR_DDCD)
-               port->icount.dcd++;
-       if (status & UART_MSR_DCTS)
-               port->icount.cts++;
-       port->mon_data.modem_status = status;
-       wake_up_interruptible(&port->delta_msr_wait);
-
-       if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-               if (status & UART_MSR_DCD)
-                       wake_up_interruptible(&port->open_wait);
-       }
-
-       if (port->flags & ASYNC_CTS_FLOW) {
-               if (port->tty->hw_stopped) {
-                       if (status & UART_MSR_CTS) {
-                               port->tty->hw_stopped = 0;
-
-                               if ((port->type != PORT_16550A) &&
-                                               (!port->board->chip_flag)) {
-                                       outb(port->IER & ~UART_IER_THRI,
-                                               port->ioaddr + UART_IER);
-                                       port->IER |= UART_IER_THRI;
-                                       outb(port->IER, port->ioaddr +
-                                                       UART_IER);
-                               }
-                               tty_wakeup(port->tty);
-                       }
-               } else {
-                       if (!(status & UART_MSR_CTS)) {
-                               port->tty->hw_stopped = 1;
-                               if (port->type != PORT_16550A &&
-                                               !port->board->chip_flag) {
-                                       port->IER &= ~UART_IER_THRI;
-                                       outb(port->IER, port->ioaddr +
-                                                       UART_IER);
-                               }
-                       }
-               }
-       }
-}
-
-static int mxser_startup(struct mxser_port *info)
-{
-       unsigned long page;
-       unsigned long flags;
-
-       page = __get_free_page(GFP_KERNEL);
-       if (!page)
-               return -ENOMEM;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               free_page(page);
-               spin_unlock_irqrestore(&info->slock, flags);
-               return 0;
-       }
-
-       if (!info->ioaddr || !info->type) {
-               if (info->tty)
-                       set_bit(TTY_IO_ERROR, &info->tty->flags);
-               free_page(page);
-               spin_unlock_irqrestore(&info->slock, flags);
-               return 0;
-       }
-       if (info->xmit_buf)
-               free_page(page);
-       else
-               info->xmit_buf = (unsigned char *) page;
-
-       /*
-        * Clear the FIFO buffers and disable them
-        * (they will be reenabled in mxser_change_speed())
-        */
-       if (info->board->chip_flag)
-               outb((UART_FCR_CLEAR_RCVR |
-                       UART_FCR_CLEAR_XMIT |
-                       MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR);
-       else
-               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
-                       info->ioaddr + UART_FCR);
-
-       /*
-        * At this point there's no way the LSR could still be 0xFF;
-        * if it is, then bail out, because there's likely no UART
-        * here.
-        */
-       if (inb(info->ioaddr + UART_LSR) == 0xff) {
-               spin_unlock_irqrestore(&info->slock, flags);
-               if (capable(CAP_SYS_ADMIN)) {
-                       if (info->tty)
-                               set_bit(TTY_IO_ERROR, &info->tty->flags);
-                       return 0;
-               } else
-                       return -ENODEV;
-       }
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) inb(info->ioaddr + UART_LSR);
-       (void) inb(info->ioaddr + UART_RX);
-       (void) inb(info->ioaddr + UART_IIR);
-       (void) inb(info->ioaddr + UART_MSR);
-
-       /*
-        * Now, initialize the UART
-        */
-       outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR);  /* reset DLAB */
-       info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-       outb(info->MCR, info->ioaddr + UART_MCR);
-
-       /*
-        * Finally, enable interrupts
-        */
-       info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-
-       if (info->board->chip_flag)
-               info->IER |= MOXA_MUST_IER_EGDAI;
-       outb(info->IER, info->ioaddr + UART_IER);       /* enable interrupts */
-
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       (void) inb(info->ioaddr + UART_LSR);
-       (void) inb(info->ioaddr + UART_RX);
-       (void) inb(info->ioaddr + UART_IIR);
-       (void) inb(info->ioaddr + UART_MSR);
-
-       if (info->tty)
-               clear_bit(TTY_IO_ERROR, &info->tty->flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-       /*
-        * and set the speed of the serial port
-        */
-       mxser_change_speed(info, NULL);
-       info->flags |= ASYNC_INITIALIZED;
-       spin_unlock_irqrestore(&info->slock, flags);
-
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts maybe disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void mxser_shutdown(struct mxser_port *info)
-{
-       unsigned long flags;
-
-       if (!(info->flags & ASYNC_INITIALIZED))
-               return;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       /*
-        * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
-        * here so the queue might never be waken up
-        */
-       wake_up_interruptible(&info->delta_msr_wait);
-
-       /*
-        * Free the IRQ, if necessary
-        */
-       if (info->xmit_buf) {
-               free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = NULL;
-       }
-
-       info->IER = 0;
-       outb(0x00, info->ioaddr + UART_IER);
-
-       if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
-               info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
-       outb(info->MCR, info->ioaddr + UART_MCR);
-
-       /* clear Rx/Tx FIFO's */
-       if (info->board->chip_flag)
-               outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
-                               MOXA_MUST_FCR_GDA_MODE_ENABLE,
-                               info->ioaddr + UART_FCR);
-       else
-               outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
-                       info->ioaddr + UART_FCR);
-
-       /* read data port to reset things */
-       (void) inb(info->ioaddr + UART_RX);
-
-       if (info->tty)
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-       info->flags &= ~ASYNC_INITIALIZED;
-
-       if (info->board->chip_flag)
-               SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
-
-       spin_unlock_irqrestore(&info->slock, flags);
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int mxser_open(struct tty_struct *tty, struct file *filp)
-{
-       struct mxser_port *info;
-       unsigned long flags;
-       int retval, line;
-
-       line = tty->index;
-       if (line == MXSER_PORTS)
-               return 0;
-       if (line < 0 || line > MXSER_PORTS)
-               return -ENODEV;
-       info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
-       if (!info->ioaddr)
-               return -ENODEV;
-
-       tty->driver_data = info;
-       info->tty = tty;
-       /*
-        * Start up serial port
-        */
-       spin_lock_irqsave(&info->slock, flags);
-       info->count++;
-       spin_unlock_irqrestore(&info->slock, flags);
-       retval = mxser_startup(info);
-       if (retval)
-               return retval;
-
-       retval = mxser_block_til_ready(tty, filp, info);
-       if (retval)
-               return retval;
-
-       /* unmark here for very high baud rate (ex. 921600 bps) used */
-       tty->low_latency = 1;
-       return 0;
-}
-
-/*
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- */
-static void mxser_close(struct tty_struct *tty, struct file *filp)
-{
-       struct mxser_port *info = tty->driver_data;
-
-       unsigned long timeout;
-       unsigned long flags;
-
-       if (tty->index == MXSER_PORTS)
-               return;
-       if (!info)
-               return;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&info->slock, flags);
-               return;
-       }
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk(KERN_ERR "mxser_close: bad serial port count; "
-                       "tty->count is 1, info->count is %d\n", info->count);
-               info->count = 1;
-       }
-       if (--info->count < 0) {
-               printk(KERN_ERR "mxser_close: bad serial port count for "
-                       "ttys%d: %d\n", tty->index, info->count);
-               info->count = 0;
-       }
-       if (info->count) {
-               spin_unlock_irqrestore(&info->slock, flags);
-               return;
-       }
-       info->flags |= ASYNC_CLOSING;
-       spin_unlock_irqrestore(&info->slock, flags);
-       /*
-        * Save the termios structure, since this port may have
-        * separate termios for callout and dialin.
-        */
-       if (info->flags & ASYNC_NORMAL_ACTIVE)
-               info->normal_termios = *tty->termios;
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
-       /*
-        * At this point we stop accepting input.  To do this, we
-        * disable the receive line status interrupts, and tell the
-        * interrupt driver to stop checking the data ready bit in the
-        * line status register.
-        */
-       info->IER &= ~UART_IER_RLSI;
-       if (info->board->chip_flag)
-               info->IER &= ~MOXA_MUST_RECV_ISR;
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               outb(info->IER, info->ioaddr + UART_IER);
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               timeout = jiffies + HZ;
-               while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
-                       schedule_timeout_interruptible(5);
-                       if (time_after(jiffies, timeout))
-                               break;
-               }
-       }
-       mxser_shutdown(info);
-
-       if (tty->driver->flush_buffer)
-               tty->driver->flush_buffer(tty);
-
-       tty_ldisc_flush(tty);
-
-       tty->closing = 0;
-       info->event = 0;
-       info->tty = NULL;
-       if (info->blocked_open) {
-               if (info->close_delay)
-                       schedule_timeout_interruptible(info->close_delay);
-               wake_up_interruptible(&info->open_wait);
-       }
-
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-}
-
-static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-       int c, total = 0;
-       struct mxser_port *info = tty->driver_data;
-       unsigned long flags;
-
-       if (!info->xmit_buf)
-               return 0;
-
-       while (1) {
-               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                         SERIAL_XMIT_SIZE - info->xmit_head));
-               if (c <= 0)
-                       break;
-
-               memcpy(info->xmit_buf + info->xmit_head, buf, c);
-               spin_lock_irqsave(&info->slock, flags);
-               info->xmit_head = (info->xmit_head + c) &
-                                 (SERIAL_XMIT_SIZE - 1);
-               info->xmit_cnt += c;
-               spin_unlock_irqrestore(&info->slock, flags);
-
-               buf += c;
-               count -= c;
-               total += c;
-       }
-
-       if (info->xmit_cnt && !tty->stopped) {
-               if (!tty->hw_stopped ||
-                               (info->type == PORT_16550A) ||
-                               (info->board->chip_flag)) {
-                       spin_lock_irqsave(&info->slock, flags);
-                       outb(info->IER & ~UART_IER_THRI, info->ioaddr +
-                                       UART_IER);
-                       info->IER |= UART_IER_THRI;
-                       outb(info->IER, info->ioaddr + UART_IER);
-                       spin_unlock_irqrestore(&info->slock, flags);
-               }
-       }
-       return total;
-}
-
-static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       struct mxser_port *info = tty->driver_data;
-       unsigned long flags;
-
-       if (!info->xmit_buf)
-               return;
-
-       if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
-               return;
-
-       spin_lock_irqsave(&info->slock, flags);
-       info->xmit_buf[info->xmit_head++] = ch;
-       info->xmit_head &= SERIAL_XMIT_SIZE - 1;
-       info->xmit_cnt++;
-       spin_unlock_irqrestore(&info->slock, flags);
-       if (!tty->stopped) {
-               if (!tty->hw_stopped ||
-                               (info->type == PORT_16550A) ||
-                               info->board->chip_flag) {
-                       spin_lock_irqsave(&info->slock, flags);
-                       outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
-                       info->IER |= UART_IER_THRI;
-                       outb(info->IER, info->ioaddr + UART_IER);
-                       spin_unlock_irqrestore(&info->slock, flags);
-               }
-       }
-}
-
-
-static void mxser_flush_chars(struct tty_struct *tty)
-{
-       struct mxser_port *info = tty->driver_data;
-       unsigned long flags;
-
-       if (info->xmit_cnt <= 0 ||
-                       tty->stopped ||
-                       !info->xmit_buf ||
-                       (tty->hw_stopped &&
-                        (info->type != PORT_16550A) &&
-                        (!info->board->chip_flag)
-                       ))
-               return;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
-       info->IER |= UART_IER_THRI;
-       outb(info->IER, info->ioaddr + UART_IER);
-
-       spin_unlock_irqrestore(&info->slock, flags);
-}
-
-static int mxser_write_room(struct tty_struct *tty)
-{
-       struct mxser_port *info = tty->driver_data;
-       int ret;
-
-       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-       if (ret < 0)
-               ret = 0;
-       return ret;
-}
-
-static int mxser_chars_in_buffer(struct tty_struct *tty)
-{
-       struct mxser_port *info = tty->driver_data;
-       return info->xmit_cnt;
-}
-
-static void mxser_flush_buffer(struct tty_struct *tty)
-{
-       struct mxser_port *info = tty->driver_data;
-       char fcr;
-       unsigned long flags;
-
-
-       spin_lock_irqsave(&info->slock, flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-       fcr = inb(info->ioaddr + UART_FCR);
-       outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
-               info->ioaddr + UART_FCR);
-       outb(fcr, info->ioaddr + UART_FCR);
-
-       spin_unlock_irqrestore(&info->slock, flags);
-
-       tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * friends of mxser_ioctl()
- * ------------------------------------------------------------
- */
-static int mxser_get_serial_info(struct mxser_port *info,
-               struct serial_struct __user *retinfo)
-{
-       struct serial_struct tmp;
-
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->tty->index;
-       tmp.port = info->ioaddr;
-       tmp.irq = info->board->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       tmp.hub6 = 0;
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int mxser_set_serial_info(struct mxser_port *info,
-               struct serial_struct __user *new_info)
-{
-       struct serial_struct new_serial;
-       unsigned long sl_flags;
-       unsigned int flags;
-       int retval = 0;
-
-       if (!new_info || !info->ioaddr)
-               return -EFAULT;
-       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
-               return -EFAULT;
-
-       if ((new_serial.irq != info->board->irq) ||
-                       (new_serial.port != info->ioaddr) ||
-                       (new_serial.custom_divisor != info->custom_divisor) ||
-                       (new_serial.baud_base != info->baud_base))
-               return -EPERM;
-
-       flags = info->flags & ASYNC_SPD_MASK;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.baud_base != info->baud_base) ||
-                               (new_serial.close_delay != info->close_delay) ||
-                               ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-                               (new_serial.flags & ASYNC_USR_MASK));
-       } else {
-               /*
-                * OK, past this point, all the error checking has been done.
-                * At this point, we start making changes.....
-                */
-               info->flags = ((info->flags & ~ASYNC_FLAGS) |
-                               (new_serial.flags & ASYNC_FLAGS));
-               info->close_delay = new_serial.close_delay * HZ / 100;
-               info->closing_wait = new_serial.closing_wait * HZ / 100;
-               info->tty->low_latency =
-                               (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-               info->tty->low_latency = 0;
-       }
-
-       info->type = new_serial.type;
-
-       process_txrx_fifo(info);
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               if (flags != (info->flags & ASYNC_SPD_MASK)) {
-                       spin_lock_irqsave(&info->slock, sl_flags);
-                       mxser_change_speed(info, NULL);
-                       spin_unlock_irqrestore(&info->slock, sl_flags);
-               }
-       } else
-               retval = mxser_startup(info);
-
-       return retval;
-}
-
-/*
- * mxser_get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space.
- */
-static int mxser_get_lsr_info(struct mxser_port *info,
-               unsigned int __user *value)
-{
-       unsigned char status;
-       unsigned int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->slock, flags);
-       status = inb(info->ioaddr + UART_LSR);
-       spin_unlock_irqrestore(&info->slock, flags);
-       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-       return put_user(result, value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void mxser_send_break(struct mxser_port *info, int duration)
-{
-       unsigned long flags;
-
-       if (!info->ioaddr)
-               return;
-       set_current_state(TASK_INTERRUPTIBLE);
-       spin_lock_irqsave(&info->slock, flags);
-       outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
-               info->ioaddr + UART_LCR);
-       spin_unlock_irqrestore(&info->slock, flags);
-       schedule_timeout(duration);
-       spin_lock_irqsave(&info->slock, flags);
-       outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
-               info->ioaddr + UART_LCR);
-       spin_unlock_irqrestore(&info->slock, flags);
-}
-
-static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct mxser_port *info = tty->driver_data;
-       unsigned char control, status;
-       unsigned long flags;
-
-
-       if (tty->index == MXSER_PORTS)
-               return -ENOIOCTLCMD;
-       if (test_bit(TTY_IO_ERROR, &tty->flags))
-               return -EIO;
-
-       control = info->MCR;
-
-       spin_lock_irqsave(&info->slock, flags);
-       status = inb(info->ioaddr + UART_MSR);
-       if (status & UART_MSR_ANY_DELTA)
-               mxser_check_modem_status(info, status);
-       spin_unlock_irqrestore(&info->slock, flags);
-       return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
-                   ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
-                   ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
-                   ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
-                   ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
-                   ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-}
-
-static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
-               unsigned int set, unsigned int clear)
-{
-       struct mxser_port *info = tty->driver_data;
-       unsigned long flags;
-
-
-       if (tty->index == MXSER_PORTS)
-               return -ENOIOCTLCMD;
-       if (test_bit(TTY_IO_ERROR, &tty->flags))
-               return -EIO;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       if (set & TIOCM_RTS)
-               info->MCR |= UART_MCR_RTS;
-       if (set & TIOCM_DTR)
-               info->MCR |= UART_MCR_DTR;
-
-       if (clear & TIOCM_RTS)
-               info->MCR &= ~UART_MCR_RTS;
-       if (clear & TIOCM_DTR)
-               info->MCR &= ~UART_MCR_DTR;
-
-       outb(info->MCR, info->ioaddr + UART_MCR);
-       spin_unlock_irqrestore(&info->slock, flags);
-       return 0;
-}
-
-static int __init mxser_program_mode(int port)
-{
-       int id, i, j, n;
-
-       outb(0, port);
-       outb(0, port);
-       outb(0, port);
-       (void)inb(port);
-       (void)inb(port);
-       outb(0, port);
-       (void)inb(port);
-
-       id = inb(port + 1) & 0x1F;
-       if ((id != C168_ASIC_ID) &&
-                       (id != C104_ASIC_ID) &&
-                       (id != C102_ASIC_ID) &&
-                       (id != CI132_ASIC_ID) &&
-                       (id != CI134_ASIC_ID) &&
-                       (id != CI104J_ASIC_ID))
-               return -1;
-       for (i = 0, j = 0; i < 4; i++) {
-               n = inb(port + 2);
-               if (n == 'M') {
-                       j = 1;
-               } else if ((j == 1) && (n == 1)) {
-                       j = 2;
-                       break;
-               } else
-                       j = 0;
-       }
-       if (j != 2)
-               id = -2;
-       return id;
-}
-
-static void __init mxser_normal_mode(int port)
-{
-       int i, n;
-
-       outb(0xA5, port + 1);
-       outb(0x80, port + 3);
-       outb(12, port + 0);     /* 9600 bps */
-       outb(0, port + 1);
-       outb(0x03, port + 3);   /* 8 data bits */
-       outb(0x13, port + 4);   /* loop back mode */
-       for (i = 0; i < 16; i++) {
-               n = inb(port + 5);
-               if ((n & 0x61) == 0x60)
-                       break;
-               if ((n & 1) == 1)
-                       (void)inb(port);
-       }
-       outb(0x00, port + 4);
-}
-
-#define CHIP_SK        0x01    /* Serial Data Clock  in Eprom */
-#define CHIP_DO        0x02    /* Serial Data Output in Eprom */
-#define CHIP_CS        0x04    /* Serial Chip Select in Eprom */
-#define CHIP_DI        0x08    /* Serial Data Input  in Eprom */
-#define EN_CCMD        0x000   /* Chip's command register     */
-#define EN0_RSARLO     0x008   /* Remote start address reg 0  */
-#define EN0_RSARHI     0x009   /* Remote start address reg 1  */
-#define EN0_RCNTLO     0x00A   /* Remote byte count reg WR    */
-#define EN0_RCNTHI     0x00B   /* Remote byte count reg WR    */
-#define EN0_DCFG       0x00E   /* Data configuration reg WR   */
-#define EN0_PORT       0x010   /* Rcv missed frame error counter RD */
-#define ENC_PAGE0      0x000   /* Select page 0 of chip registers   */
-#define ENC_PAGE3      0x0C0   /* Select page 3 of chip registers   */
-static int __init mxser_read_register(int port, unsigned short *regs)
-{
-       int i, k, value, id;
-       unsigned int j;
-
-       id = mxser_program_mode(port);
-       if (id < 0)
-               return id;
-       for (i = 0; i < 14; i++) {
-               k = (i & 0x3F) | 0x180;
-               for (j = 0x100; j > 0; j >>= 1) {
-                       outb(CHIP_CS, port);
-                       if (k & j) {
-                               outb(CHIP_CS | CHIP_DO, port);
-                               outb(CHIP_CS | CHIP_DO | CHIP_SK, port);        /* A? bit of read */
-                       } else {
-                               outb(CHIP_CS, port);
-                               outb(CHIP_CS | CHIP_SK, port);  /* A? bit of read */
-                       }
-               }
-               (void)inb(port);
-               value = 0;
-               for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
-                       outb(CHIP_CS, port);
-                       outb(CHIP_CS | CHIP_SK, port);
-                       if (inb(port) & CHIP_DI)
-                               value |= j;
-               }
-               regs[i] = value;
-               outb(0, port);
-       }
-       mxser_normal_mode(port);
-       return id;
-}
-
-static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
-{
-       struct mxser_port *port;
-       int result, status;
-       unsigned int i, j;
-
-       switch (cmd) {
-       case MOXA_GET_CONF:
-/*             if (copy_to_user(argp, mxsercfg,
-                               sizeof(struct mxser_hwconf) * 4))
-                       return -EFAULT;
-               return 0;*/
-               return -ENXIO;
-       case MOXA_GET_MAJOR:
-               if (copy_to_user(argp, &ttymajor, sizeof(int)))
-                       return -EFAULT;
-               return 0;
-
-       case MOXA_GET_CUMAJOR:
-               if (copy_to_user(argp, &calloutmajor, sizeof(int)))
-                       return -EFAULT;
-               return 0;
-
-       case MOXA_CHKPORTENABLE:
-               result = 0;
-
-               for (i = 0; i < MXSER_BOARDS; i++)
-                       for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
-                               if (mxser_boards[i].ports[j].ioaddr)
-                                       result |= (1 << i);
-
-               return put_user(result, (unsigned long __user *)argp);
-       case MOXA_GETDATACOUNT:
-               if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
-                       return -EFAULT;
-               return 0;
-       case MOXA_GETMSTATUS:
-               for (i = 0; i < MXSER_BOARDS; i++)
-                       for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
-                               port = &mxser_boards[i].ports[j];
-
-                               GMStatus[i].ri = 0;
-                               if (!port->ioaddr) {
-                                       GMStatus[i].dcd = 0;
-                                       GMStatus[i].dsr = 0;
-                                       GMStatus[i].cts = 0;
-                                       continue;
-                               }
-
-                               if (!port->tty || !port->tty->termios)
-                                       GMStatus[i].cflag =
-                                               port->normal_termios.c_cflag;
-                               else
-                                       GMStatus[i].cflag =
-                                               port->tty->termios->c_cflag;
-
-                               status = inb(port->ioaddr + UART_MSR);
-                               if (status & 0x80 /*UART_MSR_DCD */ )
-                                       GMStatus[i].dcd = 1;
-                               else
-                                       GMStatus[i].dcd = 0;
-
-                               if (status & 0x20 /*UART_MSR_DSR */ )
-                                       GMStatus[i].dsr = 1;
-                               else
-                                       GMStatus[i].dsr = 0;
-
-
-                               if (status & 0x10 /*UART_MSR_CTS */ )
-                                       GMStatus[i].cts = 1;
-                               else
-                                       GMStatus[i].cts = 0;
-                       }
-               if (copy_to_user(argp, GMStatus,
-                               sizeof(struct mxser_mstatus) * MXSER_PORTS))
-                       return -EFAULT;
-               return 0;
-       case MOXA_ASPP_MON_EXT: {
-               int p, shiftbit;
-               unsigned long opmode;
-               unsigned cflag, iflag;
-
-               for (i = 0; i < MXSER_BOARDS; i++)
-                       for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
-                               port = &mxser_boards[i].ports[j];
-                               if (!port->ioaddr)
-                                       continue;
-
-                               status = mxser_get_msr(port->ioaddr, 0, i);
-
-                               if (status & UART_MSR_TERI)
-                                       port->icount.rng++;
-                               if (status & UART_MSR_DDSR)
-                                       port->icount.dsr++;
-                               if (status & UART_MSR_DDCD)
-                                       port->icount.dcd++;
-                               if (status & UART_MSR_DCTS)
-                                       port->icount.cts++;
-
-                               port->mon_data.modem_status = status;
-                               mon_data_ext.rx_cnt[i] = port->mon_data.rxcnt;
-                               mon_data_ext.tx_cnt[i] = port->mon_data.txcnt;
-                               mon_data_ext.up_rxcnt[i] =
-                                       port->mon_data.up_rxcnt;
-                               mon_data_ext.up_txcnt[i] =
-                                       port->mon_data.up_txcnt;
-                               mon_data_ext.modem_status[i] =
-                                       port->mon_data.modem_status;
-                               mon_data_ext.baudrate[i] = port->realbaud;
-
-                               if (!port->tty || !port->tty->termios) {
-                                       cflag = port->normal_termios.c_cflag;
-                                       iflag = port->normal_termios.c_iflag;
-                               } else {
-                                       cflag = port->tty->termios->c_cflag;
-                                       iflag = port->tty->termios->c_iflag;
-                               }
-
-                               mon_data_ext.databits[i] = cflag & CSIZE;
-
-                               mon_data_ext.stopbits[i] = cflag & CSTOPB;
-
-                               mon_data_ext.parity[i] =
-                                       cflag & (PARENB | PARODD | CMSPAR);
-
-                               mon_data_ext.flowctrl[i] = 0x00;
-
-                               if (cflag & CRTSCTS)
-                                       mon_data_ext.flowctrl[i] |= 0x03;
-
-                               if (iflag & (IXON | IXOFF))
-                                       mon_data_ext.flowctrl[i] |= 0x0C;
-
-                               if (port->type == PORT_16550A)
-                                       mon_data_ext.fifo[i] = 1;
-                               else
-                                       mon_data_ext.fifo[i] = 0;
-
-                               p = i % 4;
-                               shiftbit = p * 2;
-                               opmode = inb(port->opmode_ioaddr) >> shiftbit;
-                               opmode &= OP_MODE_MASK;
-
-                               mon_data_ext.iftype[i] = opmode;
-
-                       }
-                       if (copy_to_user(argp, &mon_data_ext,
-                                               sizeof(mon_data_ext)))
-                               return -EFAULT;
-
-                       return 0;
-
-       } default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static int mxser_ioctl(struct tty_struct *tty, struct file *file,
-               unsigned int cmd, unsigned long arg)
-{
-       struct mxser_port *info = tty->driver_data;
-       struct async_icount cprev, cnow;        /* kernel counter temps */
-       struct serial_icounter_struct __user *p_cuser;
-       unsigned long templ;
-       unsigned long flags;
-       unsigned int i;
-       void __user *argp = (void __user *)arg;
-       int retval;
-
-       if (tty->index == MXSER_PORTS)
-               return mxser_ioctl_special(cmd, argp);
-
-       if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
-               int p;
-               unsigned long opmode;
-               static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
-               int shiftbit;
-               unsigned char val, mask;
-
-               p = tty->index % 4;
-               if (cmd == MOXA_SET_OP_MODE) {
-                       if (get_user(opmode, (int __user *) argp))
-                               return -EFAULT;
-                       if (opmode != RS232_MODE &&
-                                       opmode != RS485_2WIRE_MODE &&
-                                       opmode != RS422_MODE &&
-                                       opmode != RS485_4WIRE_MODE)
-                               return -EFAULT;
-                       mask = ModeMask[p];
-                       shiftbit = p * 2;
-                       val = inb(info->opmode_ioaddr);
-                       val &= mask;
-                       val |= (opmode << shiftbit);
-                       outb(val, info->opmode_ioaddr);
-               } else {
-                       shiftbit = p * 2;
-                       opmode = inb(info->opmode_ioaddr) >> shiftbit;
-                       opmode &= OP_MODE_MASK;
-                       if (copy_to_user(argp, &opmode, sizeof(int)))
-                               return -EFAULT;
-               }
-               return 0;
-       }
-
-       if (cmd == MOXA_SET_SPECIAL_BAUD_RATE) {
-               int speed;
-
-               if (get_user(speed, (int __user *)argp))
-                       return -EFAULT;
-               if (speed <= 0 || speed > info->max_baud)
-                       return -EFAULT;
-               if (!info->tty || !info->tty->termios || !info->ioaddr)
-                       return 0;
-               info->tty->termios->c_cflag &= ~(CBAUD | CBAUDEX);
-               for (i = 0; i < BAUD_TABLE_NO; i++)
-                       if (speed == mxvar_baud_table[i])
-                               break;
-               if (i == BAUD_TABLE_NO) {
-                       info->tty->termios->c_cflag |= B_SPEC;
-               } else if (speed != 0)
-                       info->tty->termios->c_cflag |= mxvar_baud_table1[i];
-
-               info->speed = speed;
-               spin_lock_irqsave(&info->slock, flags);
-               mxser_change_speed(info, NULL);
-               spin_unlock_irqrestore(&info->slock, flags);
-
-               return 0;
-       } else if (cmd == MOXA_GET_SPECIAL_BAUD_RATE) {
-               if (copy_to_user(argp, &info->speed, sizeof(int)))
-                    return -EFAULT;
-               return 0;
-       }
-
-       if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
-                       test_bit(TTY_IO_ERROR, &tty->flags))
-               return -EIO;
-
-       switch (cmd) {
-       case TCSBRK:            /* SVID version: non-zero arg --> no break */
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               tty_wait_until_sent(tty, 0);
-               if (!arg)
-                       mxser_send_break(info, HZ / 4); /* 1/4 second */
-               return 0;
-       case TCSBRKP:           /* support for POSIX tcsendbreak() */
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               tty_wait_until_sent(tty, 0);
-               mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
-               return 0;
-       case TIOCGSOFTCAR:
-               return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
-       case TIOCSSOFTCAR:
-               if (get_user(templ, (unsigned long __user *) argp))
-                       return -EFAULT;
-               arg = templ;
-               tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
-               return 0;
-       case TIOCGSERIAL:
-               return mxser_get_serial_info(info, argp);
-       case TIOCSSERIAL:
-               return mxser_set_serial_info(info, argp);
-       case TIOCSERGETLSR:     /* Get line status register */
-               return mxser_get_lsr_info(info, argp);
-               /*
-                * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-                * - mask passed in arg for lines of interest
-                *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-                * Caller should use TIOCGICOUNT to see which one it was
-                */
-       case TIOCMIWAIT:
-               spin_lock_irqsave(&info->slock, flags);
-               cnow = info->icount;    /* note the counters on entry */
-               spin_unlock_irqrestore(&info->slock, flags);
-
-               wait_event_interruptible(info->delta_msr_wait, ({
-                       cprev = cnow;
-                       spin_lock_irqsave(&info->slock, flags);
-                       cnow = info->icount;    /* atomic copy */
-                       spin_unlock_irqrestore(&info->slock, flags);
-
-                       ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                       ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                       ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                       ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
-               }));
-               break;
-       /*
-        * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-        * Return: write counters to the user passed counter struct
-        * NB: both 1->0 and 0->1 transitions are counted except for
-        *     RI where only 0->1 is counted.
-        */
-       case TIOCGICOUNT:
-               spin_lock_irqsave(&info->slock, flags);
-               cnow = info->icount;
-               spin_unlock_irqrestore(&info->slock, flags);
-               p_cuser = argp;
-               if (put_user(cnow.frame, &p_cuser->frame))
-                       return -EFAULT;
-               if (put_user(cnow.brk, &p_cuser->brk))
-                       return -EFAULT;
-               if (put_user(cnow.overrun, &p_cuser->overrun))
-                       return -EFAULT;
-               if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
-                       return -EFAULT;
-               if (put_user(cnow.parity, &p_cuser->parity))
-                       return -EFAULT;
-               if (put_user(cnow.rx, &p_cuser->rx))
-                       return -EFAULT;
-               if (put_user(cnow.tx, &p_cuser->tx))
-                       return -EFAULT;
-               put_user(cnow.cts, &p_cuser->cts);
-               put_user(cnow.dsr, &p_cuser->dsr);
-               put_user(cnow.rng, &p_cuser->rng);
-               put_user(cnow.dcd, &p_cuser->dcd);
-               return 0;
-       case MOXA_HighSpeedOn:
-               return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
-       case MOXA_SDS_RSTICOUNTER:
-               info->mon_data.rxcnt = 0;
-               info->mon_data.txcnt = 0;
-               return 0;
-       case MOXA_ASPP_SETBAUD:{
-               long baud;
-               if (get_user(baud, (long __user *)argp))
-                       return -EFAULT;
-               spin_lock_irqsave(&info->slock, flags);
-               mxser_set_baud(info, baud);
-               spin_unlock_irqrestore(&info->slock, flags);
-               return 0;
-       }
-       case MOXA_ASPP_GETBAUD:
-               if (copy_to_user(argp, &info->realbaud, sizeof(long)))
-                       return -EFAULT;
-
-               return 0;
-
-       case MOXA_ASPP_OQUEUE:{
-               int len, lsr;
-
-               len = mxser_chars_in_buffer(tty);
-
-               lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
-
-               len += (lsr ? 0 : 1);
-
-               if (copy_to_user(argp, &len, sizeof(int)))
-                       return -EFAULT;
-
-               return 0;
-       }
-       case MOXA_ASPP_MON: {
-               int mcr, status;
-
-               status = mxser_get_msr(info->ioaddr, 1, tty->index);
-               mxser_check_modem_status(info, status);
-
-               mcr = inb(info->ioaddr + UART_MCR);
-               if (mcr & MOXA_MUST_MCR_XON_FLAG)
-                       info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
-               else
-                       info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
-
-               if (mcr & MOXA_MUST_MCR_TX_XON)
-                       info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
-               else
-                       info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
-
-               if (info->tty->hw_stopped)
-                       info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
-               else
-                       info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-
-               if (copy_to_user(argp, &info->mon_data,
-                               sizeof(struct mxser_mon)))
-                       return -EFAULT;
-
-               return 0;
-       }
-       case MOXA_ASPP_LSTATUS: {
-               if (copy_to_user(argp, &info->err_shadow,
-                               sizeof(unsigned char)))
-                       return -EFAULT;
-
-               info->err_shadow = 0;
-               return 0;
-       }
-       case MOXA_SET_BAUD_METHOD: {
-               int method;
-
-               if (get_user(method, (int __user *)argp))
-                       return -EFAULT;
-               mxser_set_baud_method[tty->index] = method;
-               if (copy_to_user(argp, &method, sizeof(int)))
-                       return -EFAULT;
-
-               return 0;
-       }
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static void mxser_stoprx(struct tty_struct *tty)
-{
-       struct mxser_port *info = tty->driver_data;
-
-       info->ldisc_stop_rx = 1;
-       if (I_IXOFF(tty)) {
-               if (info->board->chip_flag) {
-                       info->IER &= ~MOXA_MUST_RECV_ISR;
-                       outb(info->IER, info->ioaddr + UART_IER);
-               } else {
-                       info->x_char = STOP_CHAR(tty);
-                       outb(0, info->ioaddr + UART_IER);
-                       info->IER |= UART_IER_THRI;
-                       outb(info->IER, info->ioaddr + UART_IER);
-               }
-       }
-
-       if (info->tty->termios->c_cflag & CRTSCTS) {
-               info->MCR &= ~UART_MCR_RTS;
-               outb(info->MCR, info->ioaddr + UART_MCR);
-       }
-}
-
-/*
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- */
-static void mxser_throttle(struct tty_struct *tty)
-{
-       mxser_stoprx(tty);
-}
-
-static void mxser_unthrottle(struct tty_struct *tty)
-{
-       struct mxser_port *info = tty->driver_data;
-
-       /* startrx */
-       info->ldisc_stop_rx = 0;
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else {
-                       if (info->board->chip_flag) {
-                               info->IER |= MOXA_MUST_RECV_ISR;
-                               outb(info->IER, info->ioaddr + UART_IER);
-                       } else {
-                               info->x_char = START_CHAR(tty);
-                               outb(0, info->ioaddr + UART_IER);
-                               info->IER |= UART_IER_THRI;
-                               outb(info->IER, info->ioaddr + UART_IER);
-                       }
-               }
-       }
-
-       if (info->tty->termios->c_cflag & CRTSCTS) {
-               info->MCR |= UART_MCR_RTS;
-               outb(info->MCR, info->ioaddr + UART_MCR);
-       }
-}
-
-/*
- * mxser_stop() and mxser_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- */
-static void mxser_stop(struct tty_struct *tty)
-{
-       struct mxser_port *info = tty->driver_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->slock, flags);
-       if (info->IER & UART_IER_THRI) {
-               info->IER &= ~UART_IER_THRI;
-               outb(info->IER, info->ioaddr + UART_IER);
-       }
-       spin_unlock_irqrestore(&info->slock, flags);
-}
-
-static void mxser_start(struct tty_struct *tty)
-{
-       struct mxser_port *info = tty->driver_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->slock, flags);
-       if (info->xmit_cnt && info->xmit_buf) {
-               outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
-               info->IER |= UART_IER_THRI;
-               outb(info->IER, info->ioaddr + UART_IER);
-       }
-       spin_unlock_irqrestore(&info->slock, flags);
-}
-
-static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct mxser_port *info = tty->driver_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->slock, flags);
-       mxser_change_speed(info, old_termios);
-       spin_unlock_irqrestore(&info->slock, flags);
-
-       if ((old_termios->c_cflag & CRTSCTS) &&
-                       !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               mxser_start(tty);
-       }
-
-       /* Handle sw stopped */
-       if ((old_termios->c_iflag & IXON) &&
-                       !(tty->termios->c_iflag & IXON)) {
-               tty->stopped = 0;
-
-               if (info->board->chip_flag) {
-                       spin_lock_irqsave(&info->slock, flags);
-                       DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
-                       spin_unlock_irqrestore(&info->slock, flags);
-               }
-
-               mxser_start(tty);
-       }
-}
-
-/*
- * mxser_wait_until_sent() --- wait until the transmitter is empty
- */
-static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       struct mxser_port *info = tty->driver_data;
-       unsigned long orig_jiffies, char_time;
-       int lsr;
-
-       if (info->type == PORT_UNKNOWN)
-               return;
-
-       if (info->xmit_fifo_size == 0)
-               return;         /* Just in case.... */
-
-       orig_jiffies = jiffies;
-       /*
-        * Set the check interval to be 1/5 of the estimated time to
-        * send a single character, and make it at least 1.  The check
-        * interval should also be less than the timeout.
-        *
-        * Note: we have to use pretty tight timings here to satisfy
-        * the NIST-PCTS.
-        */
-       char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
-       char_time = char_time / 5;
-       if (char_time == 0)
-               char_time = 1;
-       if (timeout && timeout < char_time)
-               char_time = timeout;
-       /*
-        * If the transmitter hasn't cleared in twice the approximate
-        * amount of time to send the entire FIFO, it probably won't
-        * ever clear.  This assumes the UART isn't doing flow
-        * control, which is currently the case.  Hence, if it ever
-        * takes longer than info->timeout, this is probably due to a
-        * UART bug of some kind.  So, we clamp the timeout parameter at
-        * 2*info->timeout.
-        */
-       if (!timeout || timeout > 2 * info->timeout)
-               timeout = 2 * info->timeout;
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
-               timeout, char_time);
-       printk("jiff=%lu...", jiffies);
-#endif
-       while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
-               schedule_timeout_interruptible(char_time);
-               if (signal_pending(current))
-                       break;
-               if (timeout && time_after(jiffies, orig_jiffies + timeout))
-                       break;
-       }
-       set_current_state(TASK_RUNNING);
-
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-
-/*
- * This routine is called by tty_hangup() when a hangup is signaled.
- */
-static void mxser_hangup(struct tty_struct *tty)
-{
-       struct mxser_port *info = tty->driver_data;
-
-       mxser_flush_buffer(tty);
-       mxser_shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * mxser_rs_break() --- routine which turns the break handling on or off
- */
-static void mxser_rs_break(struct tty_struct *tty, int break_state)
-{
-       struct mxser_port *info = tty->driver_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&info->slock, flags);
-       if (break_state == -1)
-               outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
-                       info->ioaddr + UART_LCR);
-       else
-               outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
-                       info->ioaddr + UART_LCR);
-       spin_unlock_irqrestore(&info->slock, flags);
-}
-
-static void mxser_receive_chars(struct mxser_port *port, int *status)
-{
-       struct tty_struct *tty = port->tty;
-       unsigned char ch, gdl;
-       int ignored = 0;
-       int cnt = 0;
-       int recv_room;
-       int max = 256;
-
-       recv_room = tty->receive_room;
-       if ((recv_room == 0) && (!port->ldisc_stop_rx))
-               mxser_stoprx(tty);
-
-       if (port->board->chip_flag != MOXA_OTHER_UART) {
-
-               if (*status & UART_LSR_SPECIAL)
-                       goto intr_old;
-               if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
-                               (*status & MOXA_MUST_LSR_RERR))
-                       goto intr_old;
-               if (*status & MOXA_MUST_LSR_RERR)
-                       goto intr_old;
-
-               gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
-
-               if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
-                       gdl &= MOXA_MUST_GDL_MASK;
-               if (gdl >= recv_room) {
-                       if (!port->ldisc_stop_rx)
-                               mxser_stoprx(tty);
-               }
-               while (gdl--) {
-                       ch = inb(port->ioaddr + UART_RX);
-                       tty_insert_flip_char(tty, ch, 0);
-                       cnt++;
-               }
-               goto end_intr;
-       }
-intr_old:
-
-       do {
-               if (max-- < 0)
-                       break;
-
-               ch = inb(port->ioaddr + UART_RX);
-               if (port->board->chip_flag && (*status & UART_LSR_OE))
-                       outb(0x23, port->ioaddr + UART_FCR);
-               *status &= port->read_status_mask;
-               if (*status & port->ignore_status_mask) {
-                       if (++ignored > 100)
-                               break;
-               } else {
-                       char flag = 0;
-                       if (*status & UART_LSR_SPECIAL) {
-                               if (*status & UART_LSR_BI) {
-                                       flag = TTY_BREAK;
-                                       port->icount.brk++;
-
-                                       if (port->flags & ASYNC_SAK)
-                                               do_SAK(tty);
-                               } else if (*status & UART_LSR_PE) {
-                                       flag = TTY_PARITY;
-                                       port->icount.parity++;
-                               } else if (*status & UART_LSR_FE) {
-                                       flag = TTY_FRAME;
-                                       port->icount.frame++;
-                               } else if (*status & UART_LSR_OE) {
-                                       flag = TTY_OVERRUN;
-                                       port->icount.overrun++;
-                               } else
-                                       flag = TTY_BREAK;
-                       }
-                       tty_insert_flip_char(tty, ch, flag);
-                       cnt++;
-                       if (cnt >= recv_room) {
-                               if (!port->ldisc_stop_rx)
-                                       mxser_stoprx(tty);
-                               break;
-                       }
-
-               }
-
-               if (port->board->chip_flag)
-                       break;
-
-               *status = inb(port->ioaddr + UART_LSR);
-       } while (*status & UART_LSR_DR);
-
-end_intr:
-       mxvar_log.rxcnt[port->tty->index] += cnt;
-       port->mon_data.rxcnt += cnt;
-       port->mon_data.up_rxcnt += cnt;
-
-       /*
-        * We are called from an interrupt context with &port->slock
-        * being held. Drop it temporarily in order to prevent
-        * recursive locking.
-        */
-       spin_unlock(&port->slock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&port->slock);
-}
-
-static void mxser_transmit_chars(struct mxser_port *port)
-{
-       int count, cnt;
-
-       if (port->x_char) {
-               outb(port->x_char, port->ioaddr + UART_TX);
-               port->x_char = 0;
-               mxvar_log.txcnt[port->tty->index]++;
-               port->mon_data.txcnt++;
-               port->mon_data.up_txcnt++;
-               port->icount.tx++;
-               return;
-       }
-
-       if (port->xmit_buf == 0)
-               return;
-
-       if ((port->xmit_cnt <= 0) || port->tty->stopped ||
-                       (port->tty->hw_stopped &&
-                       (port->type != PORT_16550A) &&
-                       (!port->board->chip_flag))) {
-               port->IER &= ~UART_IER_THRI;
-               outb(port->IER, port->ioaddr + UART_IER);
-               return;
-       }
-
-       cnt = port->xmit_cnt;
-       count = port->xmit_fifo_size;
-       do {
-               outb(port->xmit_buf[port->xmit_tail++],
-                       port->ioaddr + UART_TX);
-               port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
-               if (--port->xmit_cnt <= 0)
-                       break;
-       } while (--count > 0);
-       mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt);
-
-       port->mon_data.txcnt += (cnt - port->xmit_cnt);
-       port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
-       port->icount.tx += (cnt - port->xmit_cnt);
-
-       if (port->xmit_cnt < WAKEUP_CHARS)
-               tty_wakeup(port->tty);
-
-       if (port->xmit_cnt <= 0) {
-               port->IER &= ~UART_IER_THRI;
-               outb(port->IER, port->ioaddr + UART_IER);
-       }
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t mxser_interrupt(int irq, void *dev_id)
-{
-       int status, iir, i;
-       struct mxser_board *brd = NULL;
-       struct mxser_port *port;
-       int max, irqbits, bits, msr;
-       unsigned int int_cnt, pass_counter = 0;
-       int handled = IRQ_NONE;
-
-       for (i = 0; i < MXSER_BOARDS; i++)
-               if (dev_id == &mxser_boards[i]) {
-                       brd = dev_id;
-                       break;
-               }
-
-       if (i == MXSER_BOARDS)
-               goto irq_stop;
-       if (brd == NULL)
-               goto irq_stop;
-       max = brd->info->nports;
-       while (pass_counter++ < MXSER_ISR_PASS_LIMIT) {
-               irqbits = inb(brd->vector) & brd->vector_mask;
-               if (irqbits == brd->vector_mask)
-                       break;
-
-               handled = IRQ_HANDLED;
-               for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
-                       if (irqbits == brd->vector_mask)
-                               break;
-                       if (bits & irqbits)
-                               continue;
-                       port = &brd->ports[i];
-
-                       int_cnt = 0;
-                       spin_lock(&port->slock);
-                       do {
-                               iir = inb(port->ioaddr + UART_IIR);
-                               if (iir & UART_IIR_NO_INT)
-                                       break;
-                               iir &= MOXA_MUST_IIR_MASK;
-                               if (!port->tty ||
-                                               (port->flags & ASYNC_CLOSING) ||
-                                               !(port->flags &
-                                                       ASYNC_INITIALIZED)) {
-                                       status = inb(port->ioaddr + UART_LSR);
-                                       outb(0x27, port->ioaddr + UART_FCR);
-                                       inb(port->ioaddr + UART_MSR);
-                                       break;
-                               }
-
-                               status = inb(port->ioaddr + UART_LSR);
-
-                               if (status & UART_LSR_PE)
-                                       port->err_shadow |= NPPI_NOTIFY_PARITY;
-                               if (status & UART_LSR_FE)
-                                       port->err_shadow |= NPPI_NOTIFY_FRAMING;
-                               if (status & UART_LSR_OE)
-                                       port->err_shadow |=
-                                               NPPI_NOTIFY_HW_OVERRUN;
-                               if (status & UART_LSR_BI)
-                                       port->err_shadow |= NPPI_NOTIFY_BREAK;
-
-                               if (port->board->chip_flag) {
-                                       if (iir == MOXA_MUST_IIR_GDA ||
-                                           iir == MOXA_MUST_IIR_RDA ||
-                                           iir == MOXA_MUST_IIR_RTO ||
-                                           iir == MOXA_MUST_IIR_LSR)
-                                               mxser_receive_chars(port,
-                                                               &status);
-
-                               } else {
-                                       status &= port->read_status_mask;
-                                       if (status & UART_LSR_DR)
-                                               mxser_receive_chars(port,
-                                                               &status);
-                               }
-                               msr = inb(port->ioaddr + UART_MSR);
-                               if (msr & UART_MSR_ANY_DELTA)
-                                       mxser_check_modem_status(port, msr);
-
-                               if (port->board->chip_flag) {
-                                       if (iir == 0x02 && (status &
-                                                               UART_LSR_THRE))
-                                               mxser_transmit_chars(port);
-                               } else {
-                                       if (status & UART_LSR_THRE)
-                                               mxser_transmit_chars(port);
-                               }
-                       } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
-                       spin_unlock(&port->slock);
-               }
-       }
-
-irq_stop:
-       return handled;
-}
-
-static const struct tty_operations mxser_ops = {
-       .open = mxser_open,
-       .close = mxser_close,
-       .write = mxser_write,
-       .put_char = mxser_put_char,
-       .flush_chars = mxser_flush_chars,
-       .write_room = mxser_write_room,
-       .chars_in_buffer = mxser_chars_in_buffer,
-       .flush_buffer = mxser_flush_buffer,
-       .ioctl = mxser_ioctl,
-       .throttle = mxser_throttle,
-       .unthrottle = mxser_unthrottle,
-       .set_termios = mxser_set_termios,
-       .stop = mxser_stop,
-       .start = mxser_start,
-       .hangup = mxser_hangup,
-       .break_ctl = mxser_rs_break,
-       .wait_until_sent = mxser_wait_until_sent,
-       .tiocmget = mxser_tiocmget,
-       .tiocmset = mxser_tiocmset,
-};
-
-/*
- * The MOXA Smartio/Industio serial driver boot-time initialization code!
- */
-
-static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
-               unsigned int irq)
-{
-       if (irq)
-               free_irq(brd->irq, brd);
-       if (pdev != NULL) {     /* PCI */
-#ifdef CONFIG_PCI
-               pci_release_region(pdev, 2);
-               pci_release_region(pdev, 3);
-#endif
-       } else {
-               release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
-               release_region(brd->vector, 1);
-       }
-}
-
-static int __devinit mxser_initbrd(struct mxser_board *brd,
-               struct pci_dev *pdev)
-{
-       struct mxser_port *info;
-       unsigned int i;
-       int retval;
-
-       printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud);
-
-       for (i = 0; i < brd->info->nports; i++) {
-               info = &brd->ports[i];
-               info->board = brd;
-               info->stop_rx = 0;
-               info->ldisc_stop_rx = 0;
-
-               /* Enhance mode enabled here */
-               if (brd->chip_flag != MOXA_OTHER_UART)
-                       ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr);
-
-               info->flags = ASYNC_SHARE_IRQ;
-               info->type = brd->uart_type;
-
-               process_txrx_fifo(info);
-
-               info->custom_divisor = info->baud_base * 16;
-               info->close_delay = 5 * HZ / 10;
-               info->closing_wait = 30 * HZ;
-               info->normal_termios = mxvar_sdriver->init_termios;
-               init_waitqueue_head(&info->open_wait);
-               init_waitqueue_head(&info->delta_msr_wait);
-               info->speed = 9600;
-               memset(&info->mon_data, 0, sizeof(struct mxser_mon));
-               info->err_shadow = 0;
-               spin_lock_init(&info->slock);
-
-               /* before set INT ISR, disable all int */
-               outb(inb(info->ioaddr + UART_IER) & 0xf0,
-                       info->ioaddr + UART_IER);
-       }
-
-       retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
-                       brd);
-       if (retval) {
-               printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
-                       "conflict with another device.\n",
-                       brd->info->name, brd->irq);
-               /* We hold resources, we need to release them. */
-               mxser_release_res(brd, pdev, 0);
-       }
-       return retval;
-}
-
-static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
-{
-       int id, i, bits;
-       unsigned short regs[16], irq;
-       unsigned char scratch, scratch2;
-
-       brd->chip_flag = MOXA_OTHER_UART;
-
-       id = mxser_read_register(cap, regs);
-       switch (id) {
-       case C168_ASIC_ID:
-               brd->info = &mxser_cards[0];
-               break;
-       case C104_ASIC_ID:
-               brd->info = &mxser_cards[1];
-               break;
-       case CI104J_ASIC_ID:
-               brd->info = &mxser_cards[2];
-               break;
-       case C102_ASIC_ID:
-               brd->info = &mxser_cards[5];
-               break;
-       case CI132_ASIC_ID:
-               brd->info = &mxser_cards[6];
-               break;
-       case CI134_ASIC_ID:
-               brd->info = &mxser_cards[7];
-               break;
-       default:
-               return 0;
-       }
-
-       irq = 0;
-       /* some ISA cards have 2 ports, but we want to see them as 4-port (why?)
-          Flag-hack checks if configuration should be read as 2-port here. */
-       if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) {
-               irq = regs[9] & 0xF000;
-               irq = irq | (irq >> 4);
-               if (irq != (regs[9] & 0xFF00))
-                       return MXSER_ERR_IRQ_CONFLIT;
-       } else if (brd->info->nports == 4) {
-               irq = regs[9] & 0xF000;
-               irq = irq | (irq >> 4);
-               irq = irq | (irq >> 8);
-               if (irq != regs[9])
-                       return MXSER_ERR_IRQ_CONFLIT;
-       } else if (brd->info->nports == 8) {
-               irq = regs[9] & 0xF000;
-               irq = irq | (irq >> 4);
-               irq = irq | (irq >> 8);
-               if ((irq != regs[9]) || (irq != regs[10]))
-                       return MXSER_ERR_IRQ_CONFLIT;
-       }
-
-       if (!irq)
-               return MXSER_ERR_IRQ;
-       brd->irq = ((int)(irq & 0xF000) >> 12);
-       for (i = 0; i < 8; i++)
-               brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8;
-       if ((regs[12] & 0x80) == 0)
-               return MXSER_ERR_VECTOR;
-       brd->vector = (int)regs[11];    /* interrupt vector */
-       if (id == 1)
-               brd->vector_mask = 0x00FF;
-       else
-               brd->vector_mask = 0x000F;
-       for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
-               if (regs[12] & bits) {
-                       brd->ports[i].baud_base = 921600;
-                       brd->ports[i].max_baud = 921600;
-               } else {
-                       brd->ports[i].baud_base = 115200;
-                       brd->ports[i].max_baud = 115200;
-               }
-       }
-       scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
-       outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR);
-       outb(0, cap + UART_EFR);        /* EFR is the same as FCR */
-       outb(scratch2, cap + UART_LCR);
-       outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR);
-       scratch = inb(cap + UART_IIR);
-
-       if (scratch & 0xC0)
-               brd->uart_type = PORT_16550A;
-       else
-               brd->uart_type = PORT_16450;
-       if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
-                       "mxser(IO)"))
-               return MXSER_ERR_IOADDR;
-       if (!request_region(brd->vector, 1, "mxser(vector)")) {
-               release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
-               return MXSER_ERR_VECTOR;
-       }
-       return brd->info->nports;
-}
-
-static int __devinit mxser_probe(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
-{
-#ifdef CONFIG_PCI
-       struct mxser_board *brd;
-       unsigned int i, j;
-       unsigned long ioaddress;
-       int retval = -EINVAL;
-
-       for (i = 0; i < MXSER_BOARDS; i++)
-               if (mxser_boards[i].info == NULL)
-                       break;
-
-       if (i >= MXSER_BOARDS) {
-               printk(KERN_ERR "Too many Smartio/Industio family boards found "
-                       "(maximum %d), board not configured\n", MXSER_BOARDS);
-               goto err;
-       }
-
-       brd = &mxser_boards[i];
-       brd->idx = i * MXSER_PORTS_PER_BOARD;
-       printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
-               mxser_cards[ent->driver_data].name,
-               pdev->bus->number, PCI_SLOT(pdev->devfn));
-
-       retval = pci_enable_device(pdev);
-       if (retval) {
-               printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
-               goto err;
-       }
-
-       /* io address */
-       ioaddress = pci_resource_start(pdev, 2);
-       retval = pci_request_region(pdev, 2, "mxser(IO)");
-       if (retval)
-               goto err;
-
-       brd->info = &mxser_cards[ent->driver_data];
-       for (i = 0; i < brd->info->nports; i++)
-               brd->ports[i].ioaddr = ioaddress + 8 * i;
-
-       /* vector */
-       ioaddress = pci_resource_start(pdev, 3);
-       retval = pci_request_region(pdev, 3, "mxser(vector)");
-       if (retval)
-               goto err_relio;
-       brd->vector = ioaddress;
-
-       /* irq */
-       brd->irq = pdev->irq;
-
-       brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr);
-       brd->uart_type = PORT_16550A;
-       brd->vector_mask = 0;
-
-       for (i = 0; i < brd->info->nports; i++) {
-               for (j = 0; j < UART_INFO_NUM; j++) {
-                       if (Gpci_uart_info[j].type == brd->chip_flag) {
-                               brd->ports[i].max_baud =
-                                       Gpci_uart_info[j].max_baud;
-
-                               /* exception....CP-102 */
-                               if (brd->info->flags & MXSER_HIGHBAUD)
-                                       brd->ports[i].max_baud = 921600;
-                               break;
-                       }
-               }
-       }
-
-       if (brd->chip_flag == MOXA_MUST_MU860_HWID) {
-               for (i = 0; i < brd->info->nports; i++) {
-                       if (i < 4)
-                               brd->ports[i].opmode_ioaddr = ioaddress + 4;
-                       else
-                               brd->ports[i].opmode_ioaddr = ioaddress + 0x0c;
-               }
-               outb(0, ioaddress + 4); /* default set to RS232 mode */
-               outb(0, ioaddress + 0x0c);      /* default set to RS232 mode */
-       }
-
-       for (i = 0; i < brd->info->nports; i++) {
-               brd->vector_mask |= (1 << i);
-               brd->ports[i].baud_base = 921600;
-       }
-
-       /* mxser_initbrd will hook ISR. */
-       retval = mxser_initbrd(brd, pdev);
-       if (retval)
-               goto err_null;
-
-       for (i = 0; i < brd->info->nports; i++)
-               tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
-
-       pci_set_drvdata(pdev, brd);
-
-       return 0;
-err_relio:
-       pci_release_region(pdev, 2);
-err_null:
-       brd->info = NULL;
-err:
-       return retval;
-#else
-       return -ENODEV;
-#endif
-}
-
-static void __devexit mxser_remove(struct pci_dev *pdev)
-{
-       struct mxser_board *brd = pci_get_drvdata(pdev);
-       unsigned int i;
-
-       for (i = 0; i < brd->info->nports; i++)
-               tty_unregister_device(mxvar_sdriver, brd->idx + i);
-
-       mxser_release_res(brd, pdev, 1);
-       brd->info = NULL;
-}
-
-static struct pci_driver mxser_driver = {
-       .name = "mxser",
-       .id_table = mxser_pcibrds,
-       .probe = mxser_probe,
-       .remove = __devexit_p(mxser_remove)
-};
-
-static int __init mxser_module_init(void)
-{
-       struct mxser_board *brd;
-       unsigned long cap;
-       unsigned int i, m, isaloop;
-       int retval, b;
-
-       pr_debug("Loading module mxser ...\n");
-
-       mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
-       if (!mxvar_sdriver)
-               return -ENOMEM;
-
-       printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
-               MXSER_VERSION);
-
-       /* Initialize the tty_driver structure */
-       mxvar_sdriver->owner = THIS_MODULE;
-       mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
-       mxvar_sdriver->name = "ttyMI";
-       mxvar_sdriver->major = ttymajor;
-       mxvar_sdriver->minor_start = 0;
-       mxvar_sdriver->num = MXSER_PORTS + 1;
-       mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
-       mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
-       mxvar_sdriver->init_termios = tty_std_termios;
-       mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
-       mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
-       tty_set_operations(mxvar_sdriver, &mxser_ops);
-
-       retval = tty_register_driver(mxvar_sdriver);
-       if (retval) {
-               printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family "
-                               "tty driver !\n");
-               goto err_put;
-       }
-
-       mxvar_diagflag = 0;
-
-       m = 0;
-       /* Start finding ISA boards here */
-       for (isaloop = 0; isaloop < 2; isaloop++)
-               for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
-                       if (!isaloop)
-                               cap = mxserBoardCAP[b]; /* predefined */
-                       else
-                               cap = ioaddr[b]; /* module param */
-
-                       if (!cap)
-                               continue;
-
-                       brd = &mxser_boards[m];
-                       retval = mxser_get_ISA_conf(cap, brd);
-
-                       if (retval != 0)
-                               printk(KERN_INFO "Found MOXA %s board "
-                                       "(CAP=0x%x)\n",
-                                       brd->info->name, ioaddr[b]);
-
-                       if (retval <= 0) {
-                               if (retval == MXSER_ERR_IRQ)
-                                       printk(KERN_ERR "Invalid interrupt "
-                                               "number, board not "
-                                               "configured\n");
-                               else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                                       printk(KERN_ERR "Invalid interrupt "
-                                               "number, board not "
-                                               "configured\n");
-                               else if (retval == MXSER_ERR_VECTOR)
-                                       printk(KERN_ERR "Invalid interrupt "
-                                               "vector, board not "
-                                               "configured\n");
-                               else if (retval == MXSER_ERR_IOADDR)
-                                       printk(KERN_ERR "Invalid I/O address, "
-                                               "board not configured\n");
-
-                               brd->info = NULL;
-                               continue;
-                       }
-
-                       /* mxser_initbrd will hook ISR. */
-                       if (mxser_initbrd(brd, NULL) < 0) {
-                               brd->info = NULL;
-                               continue;
-                       }
-
-                       brd->idx = m * MXSER_PORTS_PER_BOARD;
-                       for (i = 0; i < brd->info->nports; i++)
-                               tty_register_device(mxvar_sdriver, brd->idx + i,
-                                               NULL);
-
-                       m++;
-               }
-
-       retval = pci_register_driver(&mxser_driver);
-       if (retval) {
-               printk(KERN_ERR "Can't register pci driver\n");
-               if (!m) {
-                       retval = -ENODEV;
-                       goto err_unr;
-               } /* else: we have some ISA cards under control */
-       }
-
-       pr_debug("Done.\n");
-
-       return 0;
-err_unr:
-       tty_unregister_driver(mxvar_sdriver);
-err_put:
-       put_tty_driver(mxvar_sdriver);
-       return retval;
-}
-
-static void __exit mxser_module_exit(void)
-{
-       unsigned int i, j;
-
-       pr_debug("Unloading module mxser ...\n");
-
-       pci_unregister_driver(&mxser_driver);
-
-       for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
-               if (mxser_boards[i].info != NULL)
-                       for (j = 0; j < mxser_boards[i].info->nports; j++)
-                               tty_unregister_device(mxvar_sdriver,
-                                               mxser_boards[i].idx + j);
-       tty_unregister_driver(mxvar_sdriver);
-       put_tty_driver(mxvar_sdriver);
-
-       for (i = 0; i < MXSER_BOARDS; i++)
-               if (mxser_boards[i].info != NULL)
-                       mxser_release_res(&mxser_boards[i], NULL, 1);
-
-       pr_debug("Done.\n");
-}
-
-module_init(mxser_module_init);
-module_exit(mxser_module_exit);
diff --git a/drivers/char/mxser_new.h b/drivers/char/mxser_new.h
deleted file mode 100644 (file)
index d42f776..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-#ifndef _MXSER_H
-#define _MXSER_H
-
-/*
- *     Semi-public control interfaces
- */
-
-/*
- *     MOXA ioctls
- */
-
-#define MOXA                   0x400
-#define MOXA_GETDATACOUNT      (MOXA + 23)
-#define        MOXA_GET_CONF           (MOXA + 35)
-#define MOXA_DIAGNOSE          (MOXA + 50)
-#define MOXA_CHKPORTENABLE     (MOXA + 60)
-#define MOXA_HighSpeedOn       (MOXA + 61)
-#define MOXA_GET_MAJOR         (MOXA + 63)
-#define MOXA_GET_CUMAJOR       (MOXA + 64)
-#define MOXA_GETMSTATUS                (MOXA + 65)
-#define MOXA_SET_OP_MODE       (MOXA + 66)
-#define MOXA_GET_OP_MODE       (MOXA + 67)
-
-#define RS232_MODE             0
-#define RS485_2WIRE_MODE       1
-#define RS422_MODE             2
-#define RS485_4WIRE_MODE       3
-#define OP_MODE_MASK           3
-
-#define MOXA_SDS_RSTICOUNTER   (MOXA + 69)
-#define MOXA_ASPP_OQUEUE       (MOXA + 70)
-#define MOXA_ASPP_SETBAUD      (MOXA + 71)
-#define MOXA_ASPP_GETBAUD      (MOXA + 72)
-#define MOXA_ASPP_MON          (MOXA + 73)
-#define MOXA_ASPP_LSTATUS      (MOXA + 74)
-#define MOXA_ASPP_MON_EXT      (MOXA + 75)
-#define MOXA_SET_BAUD_METHOD   (MOXA + 76)
-#define MOXA_SET_SPECIAL_BAUD_RATE     (MOXA + 77)
-#define MOXA_GET_SPECIAL_BAUD_RATE     (MOXA + 78)
-
-/* --------------------------------------------------- */
-
-#define NPPI_NOTIFY_PARITY     0x01
-#define NPPI_NOTIFY_FRAMING    0x02
-#define NPPI_NOTIFY_HW_OVERRUN 0x04
-#define NPPI_NOTIFY_SW_OVERRUN 0x08
-#define NPPI_NOTIFY_BREAK      0x10
-
-#define NPPI_NOTIFY_CTSHOLD         0x01       /* Tx hold by CTS low */
-#define NPPI_NOTIFY_DSRHOLD         0x02       /* Tx hold by DSR low */
-#define NPPI_NOTIFY_XOFFHOLD        0x08       /* Tx hold by Xoff received */
-#define NPPI_NOTIFY_XOFFXENT        0x10       /* Xoff Sent */
-
-/* follow just for Moxa Must chip define. */
-/* */
-/* when LCR register (offset 0x03) write following value, */
-/* the Must chip will enter enchance mode. And write value */
-/* on EFR (offset 0x02) bit 6,7 to change bank. */
-#define MOXA_MUST_ENTER_ENCHANCE       0xBF
-
-/* when enhance mode enable, access on general bank register */
-#define MOXA_MUST_GDL_REGISTER         0x07
-#define MOXA_MUST_GDL_MASK             0x7F
-#define MOXA_MUST_GDL_HAS_BAD_DATA     0x80
-
-#define MOXA_MUST_LSR_RERR             0x80    /* error in receive FIFO */
-/* enchance register bank select and enchance mode setting register */
-/* when LCR register equal to 0xBF */
-#define MOXA_MUST_EFR_REGISTER         0x02
-/* enchance mode enable */
-#define MOXA_MUST_EFR_EFRB_ENABLE      0x10
-/* enchance reister bank set 0, 1, 2 */
-#define MOXA_MUST_EFR_BANK0            0x00
-#define MOXA_MUST_EFR_BANK1            0x40
-#define MOXA_MUST_EFR_BANK2            0x80
-#define MOXA_MUST_EFR_BANK3            0xC0
-#define MOXA_MUST_EFR_BANK_MASK                0xC0
-
-/* set XON1 value register, when LCR=0xBF and change to bank0 */
-#define MOXA_MUST_XON1_REGISTER                0x04
-
-/* set XON2 value register, when LCR=0xBF and change to bank0 */
-#define MOXA_MUST_XON2_REGISTER                0x05
-
-/* set XOFF1 value register, when LCR=0xBF and change to bank0 */
-#define MOXA_MUST_XOFF1_REGISTER       0x06
-
-/* set XOFF2 value register, when LCR=0xBF and change to bank0 */
-#define MOXA_MUST_XOFF2_REGISTER       0x07
-
-#define MOXA_MUST_RBRTL_REGISTER       0x04
-#define MOXA_MUST_RBRTH_REGISTER       0x05
-#define MOXA_MUST_RBRTI_REGISTER       0x06
-#define MOXA_MUST_THRTL_REGISTER       0x07
-#define MOXA_MUST_ENUM_REGISTER                0x04
-#define MOXA_MUST_HWID_REGISTER                0x05
-#define MOXA_MUST_ECR_REGISTER         0x06
-#define MOXA_MUST_CSR_REGISTER         0x07
-
-/* good data mode enable */
-#define MOXA_MUST_FCR_GDA_MODE_ENABLE  0x20
-/* only good data put into RxFIFO */
-#define MOXA_MUST_FCR_GDA_ONLY_ENABLE  0x10
-
-/* enable CTS interrupt */
-#define MOXA_MUST_IER_ECTSI            0x80
-/* enable RTS interrupt */
-#define MOXA_MUST_IER_ERTSI            0x40
-/* enable Xon/Xoff interrupt */
-#define MOXA_MUST_IER_XINT             0x20
-/* enable GDA interrupt */
-#define MOXA_MUST_IER_EGDAI            0x10
-
-#define MOXA_MUST_RECV_ISR             (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
-
-/* GDA interrupt pending */
-#define MOXA_MUST_IIR_GDA              0x1C
-#define MOXA_MUST_IIR_RDA              0x04
-#define MOXA_MUST_IIR_RTO              0x0C
-#define MOXA_MUST_IIR_LSR              0x06
-
-/* recieved Xon/Xoff or specical interrupt pending */
-#define MOXA_MUST_IIR_XSC              0x10
-
-/* RTS/CTS change state interrupt pending */
-#define MOXA_MUST_IIR_RTSCTS           0x20
-#define MOXA_MUST_IIR_MASK             0x3E
-
-#define MOXA_MUST_MCR_XON_FLAG         0x40
-#define MOXA_MUST_MCR_XON_ANY          0x80
-#define MOXA_MUST_MCR_TX_XON           0x08
-
-/* software flow control on chip mask value */
-#define MOXA_MUST_EFR_SF_MASK          0x0F
-/* send Xon1/Xoff1 */
-#define MOXA_MUST_EFR_SF_TX1           0x08
-/* send Xon2/Xoff2 */
-#define MOXA_MUST_EFR_SF_TX2           0x04
-/* send Xon1,Xon2/Xoff1,Xoff2 */
-#define MOXA_MUST_EFR_SF_TX12          0x0C
-/* don't send Xon/Xoff */
-#define MOXA_MUST_EFR_SF_TX_NO         0x00
-/* Tx software flow control mask */
-#define MOXA_MUST_EFR_SF_TX_MASK       0x0C
-/* don't receive Xon/Xoff */
-#define MOXA_MUST_EFR_SF_RX_NO         0x00
-/* receive Xon1/Xoff1 */
-#define MOXA_MUST_EFR_SF_RX1           0x02
-/* receive Xon2/Xoff2 */
-#define MOXA_MUST_EFR_SF_RX2           0x01
-/* receive Xon1,Xon2/Xoff1,Xoff2 */
-#define MOXA_MUST_EFR_SF_RX12          0x03
-/* Rx software flow control mask */
-#define MOXA_MUST_EFR_SF_RX_MASK       0x03
-
-#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do {            \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr |= MOXA_MUST_EFR_EFRB_ENABLE;                     \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do {           \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE;                    \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) do {           \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
-       __efr |= MOXA_MUST_EFR_BANK0;                           \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER);    \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) do {          \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
-       __efr |= MOXA_MUST_EFR_BANK0;                           \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER);   \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define SET_MOXA_MUST_FIFO_VALUE(info) do {                    \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((info)->ioaddr+UART_LCR);                \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR);\
-       __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER);     \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
-       __efr |= MOXA_MUST_EFR_BANK1;                           \
-       outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER);     \
-       outb((u8)((info)->rx_high_water), (info)->ioaddr+       \
-                       MOXA_MUST_RBRTH_REGISTER);              \
-       outb((u8)((info)->rx_trigger), (info)->ioaddr+          \
-                       MOXA_MUST_RBRTI_REGISTER);              \
-       outb((u8)((info)->rx_low_water), (info)->ioaddr+        \
-                       MOXA_MUST_RBRTL_REGISTER);              \
-       outb(__oldlcr, (info)->ioaddr+UART_LCR);                \
-} while (0)
-
-#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do {           \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
-       __efr |= MOXA_MUST_EFR_BANK2;                           \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER);    \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do {            \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_BANK_MASK;                      \
-       __efr |= MOXA_MUST_EFR_BANK2;                           \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER);           \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) do {    \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_SF_MASK;                        \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_SF_TX_MASK;                     \
-       __efr |= MOXA_MUST_EFR_SF_TX1;                          \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do {        \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_SF_TX_MASK;                     \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_SF_RX_MASK;                     \
-       __efr |= MOXA_MUST_EFR_SF_RX1;                          \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do {        \
-       u8      __oldlcr, __efr;                                \
-       __oldlcr = inb((baseio)+UART_LCR);                      \
-       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
-       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);           \
-       __efr &= ~MOXA_MUST_EFR_SF_RX_MASK;                     \
-       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);           \
-       outb(__oldlcr, (baseio)+UART_LCR);                      \
-} while (0)
-
-#endif
index 596c7173997b577d1216d479604435053da4f92f..90c3969012a3ce5f5ddb941561a813c6a9a3349b 100644 (file)
@@ -695,17 +695,16 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
                return;
        }
        
-       if (tty->stopped && !tty->flow_stopped &&
-           I_IXON(tty) && I_IXANY(tty)) {
-               start_tty(tty);
-               return;
-       }
-       
        if (I_ISTRIP(tty))
                c &= 0x7f;
        if (I_IUCLC(tty) && L_IEXTEN(tty))
                c=tolower(c);
 
+       if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
+           ((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) ||
+            c == INTR_CHAR(tty) || c == QUIT_CHAR(tty)))
+               start_tty(tty);
+
        if (tty->closing) {
                if (I_IXON(tty)) {
                        if (c == START_CHAR(tty))
@@ -769,7 +768,21 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
                signal = SIGTSTP;
                if (c == SUSP_CHAR(tty)) {
 send_signal:
-                       isig(signal, tty, 0);
+                       /*
+                        * Echo character, and then send the signal.
+                        * Note that we do not use isig() here because we want
+                        * the order to be:
+                        * 1) flush, 2) echo, 3) signal
+                        */
+                       if (!L_NOFLSH(tty)) {
+                               n_tty_flush_buffer(tty);
+                               if (tty->driver->flush_buffer)
+                                       tty->driver->flush_buffer(tty);
+                       }
+                       if (L_ECHO(tty))
+                               echo_char(c, tty);
+                       if (tty->pgrp)
+                               kill_pgrp(tty->pgrp, signal, 1);
                        return;
                }
        }
index 8caff0ca80ffad53eab22ef4db7bd014698cedca..279ff5005cec0890e18a6292788c11fcb9299057 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/ioctl.h>
+#include <linux/synclink.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -87,8 +88,6 @@
 
 #include <asm/uaccess.h>
 
-#include "linux/synclink.h"
-
 static MGSL_PARAMS default_params = {
        MGSL_MODE_HDLC,                 /* unsigned long mode */
        0,                              /* unsigned char loopback; */
index c511a831f0c053e60220d39c1f45b94ee3a93cb7..f43c89f7c449831b2441f5f8f55441f2253a65ce 100644 (file)
@@ -1039,6 +1039,7 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count)
                p += bytes;
 
                add_entropy_words(r, buf, (bytes + 3) / 4);
+               cond_resched();
        }
 
        return 0;
index 102ece4c4e0e8050efe26b36745db83e45069e4b..8fc4fe4e38f1bdb728f751955aa69d3f9fb06dd8 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/tty_flip.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 
         ASYNC_SPD_HI       | ASYNC_SPEED_VHI    | ASYNC_SESSION_LOCKOUT | \
         ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
 
-#define RS_EVENT_WRITE_WAKEUP  0
-
 static struct tty_driver *riscom_driver;
 
+static DEFINE_SPINLOCK(riscom_lock);
+
 static struct riscom_board rc_board[RC_NBOARD] =  {
        {
                .base   = RC_IOBASE1,
@@ -217,13 +218,14 @@ static void __init rc_init_CD180(struct riscom_board const * bp)
 {
        unsigned long flags;
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        rc_out(bp, RC_CTOUT, 0);                   /* Clear timeout             */
        rc_wait_CCR(bp);                           /* Wait for CCR ready        */
        rc_out(bp, CD180_CCR, CCR_HARDRESET);      /* Reset CD180 chip          */
-       sti();
+       spin_unlock_irqrestore(&riscom_lock, flags);
        msleep(50);                                /* Delay 0.05 sec            */
-       cli();
+       spin_lock_irqsave(&riscom_lock, flags);
        rc_out(bp, CD180_GIVR, RC_ID);             /* Set ID for this chip      */
        rc_out(bp, CD180_GICR, 0);                 /* Clear all bits            */
        rc_out(bp, CD180_PILR1, RC_ACK_MINT);      /* Prio for modem intr       */
@@ -234,7 +236,7 @@ static void __init rc_init_CD180(struct riscom_board const * bp)
        rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
        rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
        
-       restore_flags(flags);
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 /* Main probing routine, also sets irq. */
@@ -310,12 +312,6 @@ out_release:
  * 
  */
 
-static inline void rc_mark_event(struct riscom_port * port, int event)
-{
-       set_bit(event, &port->event);
-       schedule_work(&port->tqueue);
-}
-
 static inline struct riscom_port * rc_get_port(struct riscom_board const * bp,
                                               unsigned char const * what)
 {
@@ -482,7 +478,7 @@ static inline void rc_transmit(struct riscom_board const * bp)
                rc_out(bp, CD180_IER, port->IER);
        }
        if (port->xmit_cnt <= port->wakeup_chars)
-               rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+               tty_wakeup(tty);
 }
 
 static inline void rc_check_modem(struct riscom_board const * bp)
@@ -501,7 +497,7 @@ static inline void rc_check_modem(struct riscom_board const * bp)
                if (rc_in(bp, CD180_MSVR) & MSVR_CD) 
                        wake_up_interruptible(&port->open_wait);
                else
-                       schedule_work(&port->tqueue_hangup);
+                       tty_hangup(tty);
        }
        
 #ifdef RISCOM_BRAIN_DAMAGED_CTS
@@ -510,7 +506,7 @@ static inline void rc_check_modem(struct riscom_board const * bp)
                        tty->hw_stopped = 0;
                        port->IER |= IER_TXRDY;
                        if (port->xmit_cnt <= port->wakeup_chars)
-                               rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+                               tty_wakeup(tty);
                } else  {
                        tty->hw_stopped = 1;
                        port->IER &= ~IER_TXRDY;
@@ -522,7 +518,7 @@ static inline void rc_check_modem(struct riscom_board const * bp)
                        tty->hw_stopped = 0;
                        port->IER |= IER_TXRDY;
                        if (port->xmit_cnt <= port->wakeup_chars)
-                               rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+                               tty_wakeup(tty);
                } else  {
                        tty->hw_stopped = 1;
                        port->IER &= ~IER_TXRDY;
@@ -812,9 +808,9 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
                }
                port->xmit_buf = (unsigned char *) tmp;
        }
-               
-       save_flags(flags); cli();
-               
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (port->tty) 
                clear_bit(TTY_IO_ERROR, &port->tty->flags);
                
@@ -825,7 +821,7 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
        rc_change_speed(bp, port);
        port->flags |= ASYNC_INITIALIZED;
                
-       restore_flags(flags);
+       spin_unlock_irqrestore(&riscom_lock, flags);
        return 0;
 }
 
@@ -901,6 +897,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        int    retval;
        int    do_clocal = 0;
        int    CD;
+       unsigned long flags;
 
        /*
         * If the device is in the middle of being closed, then block
@@ -936,19 +933,26 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
         */
        retval = 0;
        add_wait_queue(&port->open_wait, &wait);
-       cli();
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (!tty_hung_up_p(filp))
                port->count--;
-       sti();
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
+
        port->blocked_open++;
        while (1) {
-               cli();
+               spin_lock_irqsave(&riscom_lock, flags);
+
                rc_out(bp, CD180_CAR, port_No(port));
                CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
                rc_out(bp, CD180_MSVR, MSVR_RTS);
                bp->DTR &= ~(1u << port_No(port));
                rc_out(bp, RC_DTR, bp->DTR);
-               sti();
+
+               spin_unlock_irqrestore(&riscom_lock, flags);
+
                set_current_state(TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp) ||
                    !(port->flags & ASYNC_INITIALIZED)) {
@@ -1020,8 +1024,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
        
        if (!port || rc_paranoia_check(port, tty->name, "close"))
                return;
-       
-       save_flags(flags); cli();
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (tty_hung_up_p(filp))
                goto out;
        
@@ -1078,7 +1083,6 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
        tty_ldisc_flush(tty);
 
        tty->closing = 0;
-       port->event = 0;
        port->tty = NULL;
        if (port->blocked_open) {
                if (port->close_delay) {
@@ -1088,7 +1092,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
        }
        port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
        wake_up_interruptible(&port->close_wait);
-out:   restore_flags(flags);
+
+out:
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static int rc_write(struct tty_struct * tty, 
@@ -1107,34 +1113,33 @@ static int rc_write(struct tty_struct * tty,
        if (!tty || !port->xmit_buf)
                return 0;
 
-       save_flags(flags);
        while (1) {
-               cli();          
+               spin_lock_irqsave(&riscom_lock, flags);
+
                c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
                                          SERIAL_XMIT_SIZE - port->xmit_head));
-               if (c <= 0) {
-                       restore_flags(flags);
-                       break;
-               }
+               if (c <= 0)
+                       break;  /* lock continues to be held */
 
                memcpy(port->xmit_buf + port->xmit_head, buf, c);
                port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
                port->xmit_cnt += c;
-               restore_flags(flags);
+
+               spin_unlock_irqrestore(&riscom_lock, flags);
 
                buf += c;
                count -= c;
                total += c;
        }
 
-       cli();
        if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
            !(port->IER & IER_TXRDY)) {
                port->IER |= IER_TXRDY;
                rc_out(bp, CD180_CAR, port_No(port));
                rc_out(bp, CD180_IER, port->IER);
        }
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 
        return total;
 }
@@ -1150,7 +1155,7 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch)
        if (!tty || !port->xmit_buf)
                return;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
        
        if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
                goto out;
@@ -1158,7 +1163,9 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch)
        port->xmit_buf[port->xmit_head++] = ch;
        port->xmit_head &= SERIAL_XMIT_SIZE - 1;
        port->xmit_cnt++;
-out:   restore_flags(flags);
+
+out:
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static void rc_flush_chars(struct tty_struct * tty)
@@ -1173,11 +1180,13 @@ static void rc_flush_chars(struct tty_struct * tty)
            !port->xmit_buf)
                return;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->IER |= IER_TXRDY;
        rc_out(port_Board(port), CD180_CAR, port_No(port));
        rc_out(port_Board(port), CD180_IER, port->IER);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static int rc_write_room(struct tty_struct * tty)
@@ -1212,9 +1221,11 @@ static void rc_flush_buffer(struct tty_struct *tty)
        if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
                return;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
        
        tty_wakeup(tty);
 }
@@ -1231,11 +1242,15 @@ static int rc_tiocmget(struct tty_struct *tty, struct file *file)
                return -ENODEV;
 
        bp = port_Board(port);
-       save_flags(flags); cli();
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        rc_out(bp, CD180_CAR, port_No(port));
        status = rc_in(bp, CD180_MSVR);
        result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
+
        result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
                | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
                | ((status & MSVR_CD)  ? TIOCM_CAR : 0)
@@ -1256,7 +1271,8 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
 
        bp = port_Board(port);
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (set & TIOCM_RTS)
                port->MSVR |= MSVR_RTS;
        if (set & TIOCM_DTR)
@@ -1270,7 +1286,9 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
        rc_out(bp, CD180_CAR, port_No(port));
        rc_out(bp, CD180_MSVR, port->MSVR);
        rc_out(bp, RC_DTR, bp->DTR);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
+
        return 0;
 }
 
@@ -1279,7 +1297,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length
        struct riscom_board *bp = port_Board(port);
        unsigned long flags;
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->break_length = RISCOM_TPS / HZ * length;
        port->COR2 |= COR2_ETC;
        port->IER  |= IER_TXRDY;
@@ -1289,7 +1308,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length
        rc_wait_CCR(bp);
        rc_out(bp, CD180_CCR, CCR_CORCHG2);
        rc_wait_CCR(bp);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static inline int rc_set_serial_info(struct riscom_port * port,
@@ -1298,7 +1318,6 @@ static inline int rc_set_serial_info(struct riscom_port * port,
        struct serial_struct tmp;
        struct riscom_board *bp = port_Board(port);
        int change_speed;
-       unsigned long flags;
        
        if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
                return -EFAULT;
@@ -1332,9 +1351,11 @@ static inline int rc_set_serial_info(struct riscom_port * port,
                port->closing_wait = tmp.closing_wait;
        }
        if (change_speed)  {
-               save_flags(flags); cli();
+               unsigned long flags;
+
+               spin_lock_irqsave(&riscom_lock, flags);
                rc_change_speed(bp, port);
-               restore_flags(flags);
+               spin_unlock_irqrestore(&riscom_lock, flags);
        }
        return 0;
 }
@@ -1414,17 +1435,19 @@ static void rc_throttle(struct tty_struct * tty)
                return;
        
        bp = port_Board(port);
-       
-       save_flags(flags); cli();
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->MSVR &= ~MSVR_RTS;
        rc_out(bp, CD180_CAR, port_No(port));
-       if (I_IXOFF(tty))  {
+       if (I_IXOFF(tty)) {
                rc_wait_CCR(bp);
                rc_out(bp, CD180_CCR, CCR_SSCH2);
                rc_wait_CCR(bp);
        }
        rc_out(bp, CD180_MSVR, port->MSVR);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static void rc_unthrottle(struct tty_struct * tty)
@@ -1438,7 +1461,8 @@ static void rc_unthrottle(struct tty_struct * tty)
        
        bp = port_Board(port);
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->MSVR |= MSVR_RTS;
        rc_out(bp, CD180_CAR, port_No(port));
        if (I_IXOFF(tty))  {
@@ -1447,7 +1471,8 @@ static void rc_unthrottle(struct tty_struct * tty)
                rc_wait_CCR(bp);
        }
        rc_out(bp, CD180_MSVR, port->MSVR);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static void rc_stop(struct tty_struct * tty)
@@ -1461,11 +1486,13 @@ static void rc_stop(struct tty_struct * tty)
        
        bp = port_Board(port);
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->IER &= ~IER_TXRDY;
        rc_out(bp, CD180_CAR, port_No(port));
        rc_out(bp, CD180_IER, port->IER);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static void rc_start(struct tty_struct * tty)
@@ -1479,32 +1506,15 @@ static void rc_start(struct tty_struct * tty)
        
        bp = port_Board(port);
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY))  {
                port->IER |= IER_TXRDY;
                rc_out(bp, CD180_CAR, port_No(port));
                rc_out(bp, CD180_IER, port->IER);
        }
-       restore_flags(flags);
-}
 
-/*
- * This routine is called from the work queue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (workqueue) ->
- *     do_rc_hangup() -> tty->hangup() -> rc_hangup()
- * 
- */
-static void do_rc_hangup(struct work_struct *ugly_api)
-{
-       struct riscom_port      *port = container_of(ugly_api, struct riscom_port, tqueue_hangup);
-       struct tty_struct       *tty;
-       
-       tty = port->tty;
-       if (tty)
-               tty_hangup(tty);        /* FIXME: module removal race still here */
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static void rc_hangup(struct tty_struct * tty)
@@ -1518,7 +1528,6 @@ static void rc_hangup(struct tty_struct * tty)
        bp = port_Board(port);
        
        rc_shutdown_port(bp, port);
-       port->event = 0;
        port->count = 0;
        port->flags &= ~ASYNC_NORMAL_ACTIVE;
        port->tty = NULL;
@@ -1537,9 +1546,9 @@ static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termio
            tty->termios->c_iflag == old_termios->c_iflag)
                return;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
        rc_change_speed(port_Board(port), port);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&riscom_lock, flags);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
            !(tty->termios->c_cflag & CRTSCTS)) {
@@ -1548,18 +1557,6 @@ static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termio
        }
 }
 
-static void do_softint(struct work_struct *ugly_api)
-{
-       struct riscom_port      *port = container_of(ugly_api, struct riscom_port, tqueue);
-       struct tty_struct       *tty;
-       
-       if(!(tty = port->tty)) 
-               return;
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
-               tty_wakeup(tty);
-}
-
 static const struct tty_operations riscom_ops = {
        .open  = rc_open,
        .close = rc_close,
@@ -1580,7 +1577,7 @@ static const struct tty_operations riscom_ops = {
        .tiocmset = rc_tiocmset,
 };
 
-static inline int rc_init_drivers(void)
+static int __init rc_init_drivers(void)
 {
        int error;
        int i;
@@ -1612,8 +1609,6 @@ static inline int rc_init_drivers(void)
        memset(rc_port, 0, sizeof(rc_port));
        for (i = 0; i < RC_NPORT * RC_NBOARD; i++)  {
                rc_port[i].magic = RISCOM8_MAGIC;
-               INIT_WORK(&rc_port[i].tqueue, do_softint);
-               INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup);
                rc_port[i].close_delay = 50 * HZ/100;
                rc_port[i].closing_wait = 3000 * HZ/100;
                init_waitqueue_head(&rc_port[i].open_wait);
@@ -1627,11 +1622,12 @@ static void rc_release_drivers(void)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        tty_unregister_driver(riscom_driver);
        put_tty_driver(riscom_driver);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 #ifndef MODULE
index 9cc1313d5e67934deb7819d31d8a26bf3ff71bdb..cdfdf4394477705caa0296a305e81eb6c36c1096 100644 (file)
@@ -71,7 +71,6 @@ struct riscom_port {
        struct tty_struct       * tty;
        int                     count;
        int                     blocked_open;
-       unsigned long           event; /* long req'd for set_bit --RR */
        int                     timeout;
        int                     close_delay;
        unsigned char           * xmit_buf;
@@ -81,8 +80,6 @@ struct riscom_port {
        int                     xmit_cnt;
        wait_queue_head_t       open_wait;
        wait_queue_head_t       close_wait;
-       struct work_struct      tqueue;
-       struct work_struct      tqueue_hangup;
        short                   wakeup_chars;
        short                   break_length;
        unsigned short          closing_wait;
index d83419c3857e92baa4d28a8a53806b4b465484a4..68c289fe2dc2c67ef49e4541ba22278f94a15f94 100644 (file)
  */
 
 /****** Defines ******/
-#ifdef PCI_NUM_RESOURCES
-#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start)
-#else
-#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r])
-#endif
-
 #define ROCKET_PARANOIA_CHECK
 #define ROCKET_DISABLE_SIMUSAGE
 
@@ -305,8 +299,8 @@ static inline int rocket_paranoia_check(struct r_port *info,
        if (!info)
                return 1;
        if (info->magic != RPORT_MAGIC) {
-               printk(KERN_INFO "Warning: bad magic number for rocketport struct in %s\n",
-                    routine);
+               printk(KERN_WARNING "Warning: bad magic number for rocketport "
+                               "struct in %s\n", routine);
                return 1;
        }
 #endif
@@ -328,7 +322,7 @@ static void rp_do_receive(struct r_port *info,
 
        ToRecv = sGetRxCnt(cp);
 #ifdef ROCKET_DEBUG_INTR
-       printk(KERN_INFO "rp_do_receive(%d)...", ToRecv);
+       printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv);
 #endif
        if (ToRecv == 0)
                return;
@@ -341,7 +335,7 @@ static void rp_do_receive(struct r_port *info,
        if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
                if (!(ChanStatus & STATMODE)) {
 #ifdef ROCKET_DEBUG_RECEIVE
-                       printk(KERN_INFO "Entering STATMODE...");
+                       printk(KERN_INFO "Entering STATMODE...\n");
 #endif
                        ChanStatus |= STATMODE;
                        sEnRxStatusMode(cp);
@@ -355,15 +349,15 @@ static void rp_do_receive(struct r_port *info,
         */
        if (ChanStatus & STATMODE) {
 #ifdef ROCKET_DEBUG_RECEIVE
-               printk(KERN_INFO "Ignore %x, read %x...", info->ignore_status_mask,
-                      info->read_status_mask);
+               printk(KERN_INFO "Ignore %x, read %x...\n",
+                       info->ignore_status_mask, info->read_status_mask);
 #endif
                while (ToRecv) {
                        char flag;
 
                        CharNStat = sInW(sGetTxRxDataIO(cp));
 #ifdef ROCKET_DEBUG_RECEIVE
-                       printk(KERN_INFO "%x...", CharNStat);
+                       printk(KERN_INFO "%x...\n", CharNStat);
 #endif
                        if (CharNStat & STMBREAKH)
                                CharNStat &= ~(STMFRAMEH | STMPARITYH);
@@ -435,12 +429,13 @@ static void rp_do_transmit(struct r_port *info)
        unsigned long flags;
 
 #ifdef ROCKET_DEBUG_INTR
-       printk(KERN_INFO "rp_do_transmit ");
+       printk(KERN_DEBUG "%s\n", __func__);
 #endif
        if (!info)
                return;
        if (!info->tty) {
-               printk(KERN_INFO  "rp: WARNING rp_do_transmit called with info->tty==NULL\n");
+               printk(KERN_WARNING "rp: WARNING %s called with "
+                               "info->tty==NULL\n", __func__);
                clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
                return;
        }
@@ -464,7 +459,7 @@ static void rp_do_transmit(struct r_port *info)
                info->xmit_cnt -= c;
                info->xmit_fifo_room -= c;
 #ifdef ROCKET_DEBUG_INTR
-               printk(KERN_INFO "tx %d chars...", c);
+               printk(KERN_INFO "tx %d chars...\n", c);
 #endif
        }
 
@@ -481,7 +476,7 @@ static void rp_do_transmit(struct r_port *info)
        spin_unlock_irqrestore(&info->slock, flags);
 
 #ifdef ROCKET_DEBUG_INTR
-       printk(KERN_INFO "(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head,
+       printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
               info->xmit_tail, info->xmit_fifo_room);
 #endif
 }
@@ -501,11 +496,13 @@ static void rp_handle_port(struct r_port *info)
                return;
 
        if ((info->flags & ROCKET_INITIALIZED) == 0) {
-               printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n");
+               printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
+                               "info->flags & NOT_INIT\n");
                return;
        }
        if (!info->tty) {
-               printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->tty==NULL\n");
+               printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
+                               "info->tty==NULL\n");
                return;
        }
        cp = &info->channel;
@@ -513,7 +510,7 @@ static void rp_handle_port(struct r_port *info)
 
        IntMask = sGetChanIntID(cp) & info->intmask;
 #ifdef ROCKET_DEBUG_INTR
-       printk(KERN_INFO "rp_interrupt %02x...", IntMask);
+       printk(KERN_INFO "rp_interrupt %02x...\n", IntMask);
 #endif
        ChanStatus = sGetChanStatus(cp);
        if (IntMask & RXF_TRIG) {       /* Rx FIFO trigger level */
@@ -521,7 +518,7 @@ static void rp_handle_port(struct r_port *info)
        }
        if (IntMask & DELTA_CD) {       /* CD change  */
 #if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))
-               printk(KERN_INFO "ttyR%d CD now %s...", info->line,
+               printk(KERN_INFO "ttyR%d CD now %s...\n", info->line,
                       (ChanStatus & CD_ACT) ? "on" : "off");
 #endif
                if (!(ChanStatus & CD_ACT) && info->cd_status) {
@@ -638,7 +635,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
        /*  Get a r_port struct for the port, fill it in and save it globally, indexed by line number */
        info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
        if (!info) {
-               printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line);
+               printk(KERN_ERR "Couldn't allocate info struct for line #%d\n",
+                               line);
                return;
        }
 
@@ -668,7 +666,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
 
        info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;
        if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
-               printk(KERN_INFO "RocketPort sInitChan(%d, %d, %d) failed!\n", board, aiop, chan);
+               printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
+                               board, aiop, chan);
                kfree(info);
                return;
        }
@@ -976,7 +975,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
        CHANNEL_t *cp;
        unsigned long page;
 
-       line = TTY_GET_LINE(tty);
+       line = tty->index;
        if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL))
                return -ENXIO;
 
@@ -1007,7 +1006,8 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
                atomic_inc(&rp_num_ports_open);
 
 #ifdef ROCKET_DEBUG_OPEN
-               printk(KERN_INFO "rocket mod++ = %d...", atomic_read(&rp_num_ports_open));
+               printk(KERN_INFO "rocket mod++ = %d...\n",
+                               atomic_read(&rp_num_ports_open));
 #endif
        }
 #ifdef ROCKET_DEBUG_OPEN
@@ -1103,13 +1103,13 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
                 * one, we've got real problems, since it means the
                 * serial port won't be shutdown.
                 */
-               printk(KERN_INFO "rp_close: bad serial port count; tty->count is 1, "
-                      "info->count is %d\n", info->count);
+               printk(KERN_WARNING "rp_close: bad serial port count; "
+                       "tty->count is 1, info->count is %d\n", info->count);
                info->count = 1;
        }
        if (--info->count < 0) {
-               printk(KERN_INFO "rp_close: bad serial port count for ttyR%d: %d\n",
-                      info->line, info->count);
+               printk(KERN_WARNING "rp_close: bad serial port count for "
+                               "ttyR%d: %d\n", info->line, info->count);
                info->count = 0;
        }
        if (info->count) {
@@ -1160,8 +1160,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
        if (C_HUPCL(tty))
                sClrDTR(cp);
 
-       if (TTY_DRIVER_FLUSH_BUFFER_EXISTS(tty))
-               TTY_DRIVER_FLUSH_BUFFER(tty);
+       rp_flush_buffer(tty);
                
        tty_ldisc_flush(tty);
 
@@ -1184,7 +1183,8 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
        atomic_dec(&rp_num_ports_open);
 
 #ifdef ROCKET_DEBUG_OPEN
-       printk(KERN_INFO "rocket mod-- = %d...", atomic_read(&rp_num_ports_open));
+       printk(KERN_INFO "rocket mod-- = %d...\n",
+                       atomic_read(&rp_num_ports_open));
        printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);
 #endif
 
@@ -1569,9 +1569,9 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
 
        orig_jiffies = jiffies;
 #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
-       printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...", timeout,
+       printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
               jiffies);
-       printk(KERN_INFO "cps=%d...", info->cps);
+       printk(KERN_INFO "cps=%d...\n", info->cps);
 #endif
        while (1) {
                txcnt = sGetTxCnt(cp);
@@ -1592,7 +1592,8 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
                if (check_time == 0)
                        check_time = 1;
 #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
-               printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...", txcnt, jiffies, check_time);
+               printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt,
+                               jiffies, check_time);
 #endif
                msleep_interruptible(jiffies_to_msecs(check_time));
                if (signal_pending(current))
@@ -1616,7 +1617,7 @@ static void rp_hangup(struct tty_struct *tty)
                return;
 
 #if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
-       printk(KERN_INFO "rp_hangup of ttyR%d...", info->line);
+       printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
 #endif
        rp_flush_buffer(tty);
        if (info->flags & ROCKET_CLOSING)
@@ -1664,7 +1665,7 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch)
        mutex_lock(&info->write_mtx);
 
 #ifdef ROCKET_DEBUG_WRITE
-       printk(KERN_INFO "rp_put_char %c...", ch);
+       printk(KERN_INFO "rp_put_char %c...\n", ch);
 #endif
 
        spin_lock_irqsave(&info->slock, flags);
@@ -1709,7 +1710,7 @@ static int rp_write(struct tty_struct *tty,
                return -ERESTARTSYS;
 
 #ifdef ROCKET_DEBUG_WRITE
-       printk(KERN_INFO "rp_write %d chars...", count);
+       printk(KERN_INFO "rp_write %d chars...\n", count);
 #endif
        cp = &info->channel;
 
@@ -1798,7 +1799,7 @@ static int rp_write_room(struct tty_struct *tty)
        if (ret < 0)
                ret = 0;
 #ifdef ROCKET_DEBUG_WRITE
-       printk(KERN_INFO "rp_write_room returns %d...", ret);
+       printk(KERN_INFO "rp_write_room returns %d...\n", ret);
 #endif
        return ret;
 }
@@ -1818,7 +1819,7 @@ static int rp_chars_in_buffer(struct tty_struct *tty)
        cp = &info->channel;
 
 #ifdef ROCKET_DEBUG_WRITE
-       printk(KERN_INFO "rp_chars_in_buffer returns %d...", info->xmit_cnt);
+       printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
 #endif
        return info->xmit_cnt;
 }
@@ -2161,14 +2162,11 @@ static __init int register_PCI(int i, struct pci_dev *dev)
        for (aiop = 0; aiop < max_num_aiops; aiop++)
                ctlp->AiopNumChan[aiop] = ports_per_aiop;
 
-       printk("Comtrol PCI controller #%d ID 0x%x found in bus:slot:fn %s at address %04lx, "
-            "%d AIOP(s) (%s)\n", i, dev->device, pci_name(dev),
-            rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString);
-       printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n",
-              rocketModel[i].modelString,
-              rocketModel[i].startingPortNumber,
-              rocketModel[i].startingPortNumber +
-              rocketModel[i].numPorts - 1);
+       dev_info(&dev->dev, "comtrol PCI controller #%d found at "
+               "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n",
+               i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString,
+               rocketModel[i].startingPortNumber,
+               rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1);
 
        if (num_aiops <= 0) {
                rcktpt_io_addr[i] = 0;
@@ -2191,10 +2189,10 @@ static __init int register_PCI(int i, struct pci_dev *dev)
                num_chan = ports_per_aiop;
                for (chan = 0; chan < num_chan; chan++)
                        sPCIModemReset(ctlp, chan, 1);
-               mdelay(500);
+               msleep(500);
                for (chan = 0; chan < num_chan; chan++)
                        sPCIModemReset(ctlp, chan, 0);
-               mdelay(500);
+               msleep(500);
                rmSpeakerReset(ctlp, rocketModel[i].model);
        }
        return (1);
@@ -2240,7 +2238,9 @@ static int __init init_ISA(int i)
 
        /*  Reserve the IO region */
        if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) {
-               printk(KERN_INFO "Unable to reserve IO region for configured ISA RocketPort at address 0x%lx, board not installed...\n", rcktpt_io_addr[i]);
+               printk(KERN_ERR "Unable to reserve IO region for configured "
+                               "ISA RocketPort at address 0x%lx, board not "
+                               "installed...\n", rcktpt_io_addr[i]);
                rcktpt_io_addr[i] = 0;
                return (0);
        }
@@ -2309,10 +2309,10 @@ static int __init init_ISA(int i)
                total_num_chan = num_chan;
                for (chan = 0; chan < num_chan; chan++)
                        sModemReset(ctlp, chan, 1);
-               mdelay(500);
+               msleep(500);
                for (chan = 0; chan < num_chan; chan++)
                        sModemReset(ctlp, chan, 0);
-               mdelay(500);
+               msleep(500);
                strcpy(rocketModel[i].modelString, "RocketModem ISA");
        } else {
                strcpy(rocketModel[i].modelString, "RocketPort ISA");
@@ -2480,7 +2480,7 @@ static void rp_cleanup_module(void)
 
        retval = tty_unregister_driver(rocket_driver);
        if (retval)
-               printk(KERN_INFO "Error %d while trying to unregister "
+               printk(KERN_ERR "Error %d while trying to unregister "
                       "rocketport driver\n", -retval);
 
        for (i = 0; i < MAX_RP_PORTS; i++)
index 55b8f2d71a9617d3be3c3d932b34002636d52afe..f3a75791b8111abb7654ebbda2017d3ccf4da09a 100644 (file)
@@ -42,7 +42,7 @@ typedef unsigned int DWordIO_t;
 static inline void sOutB(unsigned short port, unsigned char value)
 {
 #ifdef ROCKET_DEBUG_IO
-       printk("sOutB(%x, %x)...", port, value);
+       printk(KERN_DEBUG "sOutB(%x, %x)...\n", port, value);
 #endif
        outb_p(value, port);
 }
@@ -50,7 +50,7 @@ static inline void sOutB(unsigned short port, unsigned char value)
 static inline void sOutW(unsigned short port, unsigned short value)
 {
 #ifdef ROCKET_DEBUG_IO
-       printk("sOutW(%x, %x)...", port, value);
+       printk(KERN_DEBUG "sOutW(%x, %x)...\n", port, value);
 #endif
        outw_p(value, port);
 }
@@ -58,7 +58,7 @@ static inline void sOutW(unsigned short port, unsigned short value)
 static inline void sOutDW(unsigned short port, unsigned long value)
 {
 #ifdef ROCKET_DEBUG_IO
-       printk("sOutDW(%x, %lx)...", port, value);
+       printk(KERN_DEBUG "sOutDW(%x, %lx)...\n", port, value);
 #endif
        outl_p(cpu_to_le32(value), port);
 }
@@ -105,12 +105,6 @@ static inline unsigned short sInW(unsigned short port)
 #define AIOPID_NULL -1         /* no AIOP or channel exists */
 #define AIOPID_0001 0x0001     /* AIOP release 1 */
 
-#define NULLDEV -1             /* identifies non-existant device */
-#define NULLCTL -1             /* identifies non-existant controller */
-#define NULLCTLPTR (CONTROLLER_T *)0   /* identifies non-existant controller */
-#define NULLAIOP -1            /* identifies non-existant AIOP */
-#define NULLCHAN -1            /* identifies non-existant channel */
-
 /************************************************************************
  Global Register Offsets - Direct Access - Fixed values
 ************************************************************************/
@@ -1187,9 +1181,6 @@ struct r_port {
 #define ROCKET_CLOSING         0x40000000      /* Serial port is closing */
 #define ROCKET_NORMAL_ACTIVE   0x20000000      /* Normal port is active */
 
-/* tty subtypes */
-#define SERIAL_TYPE_NORMAL 1
-
 /*
  * Assigned major numbers for the Comtrol Rocketport
  */
@@ -1240,12 +1231,3 @@ struct r_port {
 /* Compact PCI device */ 
 #define PCI_DEVICE_ID_CRP16INTF                0x0903  /* Rocketport Compact PCI 16 port w/external I/F */
 
-#define TTY_GET_LINE(t) t->index
-#define TTY_DRIVER_MINOR_START(t) t->driver->minor_start
-#define TTY_DRIVER_SUBTYPE(t) t->driver->subtype
-#define TTY_DRIVER_NAME(t) t->driver->name
-#define TTY_DRIVER_NAME_BASE(t) t->driver->name_base
-#define TTY_DRIVER_FLUSH_BUFFER_EXISTS(t) t->driver->flush_buffer
-#define TTY_DRIVER_FLUSH_BUFFER(t) t->driver->flush_buffer(t)
-
-
index 3c869145bfdcb1169ab41c4a49633051212ab964..4ba3aec9e1cd0dc50444c05857467ade96a0fc4e 100644 (file)
@@ -653,7 +653,7 @@ static void a2232_init_portstructs(void)
                port->gs.closing_wait = 30 * HZ;
                port->gs.rd = &a2232_real_driver;
 #ifdef NEW_WRITE_LOCKING
-               init_MUTEX(&(port->gs.port_write_mutex));
+               mutex_init(&(port->gs.port_write_mutex));
 #endif
                init_waitqueue_head(&port->gs.open_wait);
                init_waitqueue_head(&port->gs.close_wait);
index f1497cecffd815248a7eb374a0346e4e8fb88e2f..df8cd0ca97ebcc5d8728ab36ffcdeabcd899c4f3 100644 (file)
@@ -90,8 +90,6 @@
 
 #define STD_COM_FLAGS (0)
 
-#define SERIAL_TYPE_NORMAL  1
-
 static struct tty_driver *cy_serial_driver;
 extern int serial_console;
 static struct cyclades_port *serial_console_info = NULL;
@@ -359,18 +357,6 @@ static void cy_start(struct tty_struct *tty)
        local_irq_restore(flags);
 }                              /* cy_start */
 
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver
- * (also known as the "bottom half").  This can be called any
- * number of times for any channel without harm.
- */
-static inline void cy_sched_event(struct cyclades_port *info, int event)
-{
-       info->event |= 1 << event;      /* remember what kind of event and who */
-       schedule_work(&info->tqueue);
-}                              /* cy_sched_event */
-
 /* The real interrupt service routines are called
    whenever the card wants its hand held--chars
    received, out buffer empty, modem change, etc.
@@ -485,10 +471,12 @@ static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
                    && (info->flags & ASYNC_CHECK_CD)) {
                        if (mdm_status & CyDCD) {
 /* CP('!'); */
-                               cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
+                               wake_up_interruptible(&info->open_wait);
                        } else {
 /* CP('@'); */
-                               cy_sched_event(info, Cy_EVENT_HANGUP);
+                               tty_hangup(info->tty);
+                               wake_up_interruptible(&info->open_wait);
+                               info->flags &= ~ASYNC_NORMAL_ACTIVE;
                        }
                }
                if ((mdm_change & CyCTS)
@@ -498,8 +486,7 @@ static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
                                        /* !!! cy_start isn't used because... */
                                        info->tty->stopped = 0;
                                        base_addr[CyIER] |= CyTxMpty;
-                                       cy_sched_event(info,
-                                                      Cy_EVENT_WRITE_WAKEUP);
+                                       tty_wakeup(info->tty);
                                }
                        } else {
                                if (!(mdm_status & CyCTS)) {
@@ -545,9 +532,6 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
        info->last_active = jiffies;
        if (info->tty == 0) {
                base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
-               if (info->xmit_cnt < WAKEUP_CHARS) {
-                       cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
-               }
                base_addr[CyTEOIR] = CyNOTRANS;
                return IRQ_HANDLED;
        }
@@ -629,9 +613,9 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
                }
        }
 
-       if (info->xmit_cnt < WAKEUP_CHARS) {
-               cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
-       }
+       if (info->xmit_cnt < WAKEUP_CHARS)
+               tty_wakeup(info->tty);
+
        base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
        return IRQ_HANDLED;
 }                              /* cy_tx_interrupt */
@@ -692,49 +676,6 @@ static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }                              /* cy_rx_interrupt */
 
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using cy_sched_event(), and they get done here.
- *
- * This is done through one level of indirection--the task queue.
- * When a hardware interrupt service routine wants service by the
- * driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the keventd work queue and sets a request flag
- * that the work queue be processed.
- *
- * Although this may seem unwieldy, it gives the system a way to
- * pass an argument (in this case the pointer to the cyclades_port
- * structure) to the bottom half of the driver.  Previous kernels
- * had to poll every port to see if that port needed servicing.
- */
-static void do_softint(struct work_struct *ugly_api)
-{
-       struct cyclades_port *info =
-           container_of(ugly_api, struct cyclades_port, tqueue);
-       struct tty_struct *tty;
-
-       tty = info->tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
-               tty_hangup(info->tty);
-               wake_up_interruptible(&info->open_wait);
-               info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       }
-       if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
-               wake_up_interruptible(&info->open_wait);
-       }
-       if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
-               tty_wakeup(tty);
-       }
-}                              /* do_softint */
-
 /* This is called whenever a port becomes active;
    interrupts are enabled and DTR & RTS are turned on.
  */
@@ -1745,7 +1686,6 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
        if (tty->driver->flush_buffer)
                tty->driver->flush_buffer(tty);
        tty_ldisc_flush(tty);
-       info->event = 0;
        info->tty = NULL;
        if (info->blocked_open) {
                if (info->close_delay) {
@@ -2236,7 +2176,6 @@ static int __init serial167_init(void)
                                info->rco = baud_co[DefSpeed] >> 5;     /* Rx CO */
                                info->close_delay = 0;
                                info->x_char = 0;
-                               info->event = 0;
                                info->count = 0;
 #ifdef SERIAL_DEBUG_COUNT
                                printk("cyc: %d: setting count to 0\n",
@@ -2245,7 +2184,6 @@ static int __init serial167_init(void)
                                info->blocked_open = 0;
                                info->default_threshold = 0;
                                info->default_timeout = 0;
-                               INIT_WORK(&info->tqueue, do_softint);
                                init_waitqueue_head(&info->open_wait);
                                init_waitqueue_head(&info->close_wait);
                                /* info->session */
index 455855631aeff70f441e26be40f3a745a4cb5609..c0e08c7bca2f4ef713c966eeed532164d33282e6 100644 (file)
@@ -178,9 +178,6 @@ static int sx_poll = HZ;
         ASYNC_SPD_HI       | ASYNC_SPEED_VHI    | ASYNC_SESSION_LOCKOUT | \
         ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
 
-#undef RS_EVENT_WRITE_WAKEUP
-#define RS_EVENT_WRITE_WAKEUP  0
-
 static struct tty_driver *specialix_driver;
 
 static struct specialix_board sx_board[SX_NBOARD] =  {
@@ -602,17 +599,6 @@ static int sx_probe(struct specialix_board *bp)
  *  Interrupt processing routines.
  * */
 
-static inline void sx_mark_event(struct specialix_port * port, int event)
-{
-       func_enter();
-
-       set_bit(event, &port->event);
-       schedule_work(&port->tqueue);
-
-       func_exit();
-}
-
-
 static inline struct specialix_port * sx_get_port(struct specialix_board * bp,
                                               unsigned char const * what)
 {
@@ -809,7 +795,7 @@ static inline void sx_transmit(struct specialix_board * bp)
                sx_out(bp, CD186x_IER, port->IER);
        }
        if (port->xmit_cnt <= port->wakeup_chars)
-               sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+               tty_wakeup(tty);
 
        func_exit();
 }
@@ -839,7 +825,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
                        wake_up_interruptible(&port->open_wait);
                } else {
                        dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");
-                       schedule_work(&port->tqueue_hangup);
+                       tty_hangup(tty);
                }
        }
 
@@ -849,7 +835,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
                        tty->hw_stopped = 0;
                        port->IER |= IER_TXRDY;
                        if (port->xmit_cnt <= port->wakeup_chars)
-                               sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+                               tty_wakeup(tty);
                } else {
                        tty->hw_stopped = 1;
                        port->IER &= ~IER_TXRDY;
@@ -861,7 +847,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
                        tty->hw_stopped = 0;
                        port->IER |= IER_TXRDY;
                        if (port->xmit_cnt <= port->wakeup_chars)
-                               sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+                               tty_wakeup(tty);
                } else {
                        tty->hw_stopped = 1;
                        port->IER &= ~IER_TXRDY;
@@ -1618,7 +1604,6 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
        tty_ldisc_flush(tty);
        spin_lock_irqsave(&port->lock, flags);
        tty->closing = 0;
-       port->event = 0;
        port->tty = NULL;
        spin_unlock_irqrestore(&port->lock, flags);
        if (port->blocked_open) {
@@ -2235,32 +2220,6 @@ static void sx_start(struct tty_struct * tty)
        func_exit();
 }
 
-
-/*
- * This routine is called from the work-queue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (workqueue) ->
- *     do_sx_hangup() -> tty->hangup() -> sx_hangup()
- *
- */
-static void do_sx_hangup(struct work_struct *work)
-{
-       struct specialix_port   *port =
-               container_of(work, struct specialix_port, tqueue_hangup);
-       struct tty_struct       *tty;
-
-       func_enter();
-
-       tty = port->tty;
-       if (tty)
-               tty_hangup(tty);        /* FIXME: module removal race here */
-
-       func_exit();
-}
-
-
 static void sx_hangup(struct tty_struct * tty)
 {
        struct specialix_port *port = (struct specialix_port *)tty->driver_data;
@@ -2278,7 +2237,6 @@ static void sx_hangup(struct tty_struct * tty)
 
        sx_shutdown_port(bp, port);
        spin_lock_irqsave(&port->lock, flags);
-       port->event = 0;
        bp->count -= port->count;
        if (bp->count < 0) {
                printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",
@@ -2320,26 +2278,6 @@ static void sx_set_termios(struct tty_struct * tty, struct ktermios * old_termio
        }
 }
 
-
-static void do_softint(struct work_struct *work)
-{
-       struct specialix_port   *port =
-               container_of(work, struct specialix_port, tqueue);
-       struct tty_struct       *tty;
-
-       func_enter();
-
-       if(!(tty = port->tty)) {
-               func_exit();
-               return;
-       }
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
-               tty_wakeup(tty);
-
-       func_exit();
-}
-
 static const struct tty_operations sx_ops = {
        .open  = sx_open,
        .close = sx_close,
@@ -2397,8 +2335,6 @@ static int sx_init_drivers(void)
        memset(sx_port, 0, sizeof(sx_port));
        for (i = 0; i < SX_NPORT * SX_NBOARD; i++) {
                sx_port[i].magic = SPECIALIX_MAGIC;
-               INIT_WORK(&sx_port[i].tqueue, do_softint);
-               INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup);
                sx_port[i].close_delay = 50 * HZ/100;
                sx_port[i].closing_wait = 3000 * HZ/100;
                init_waitqueue_head(&sx_port[i].open_wait);
index 895bd90de3631ac49941129a1ed015747090020f..3f2f85bdf51649218dedf30c6f1bbda3c9d4e134 100644 (file)
@@ -112,7 +112,6 @@ struct specialix_port {
        struct tty_struct       * tty;
        int                     count;
        int                     blocked_open;
-       ulong                   event;
        int                     timeout;
        int                     close_delay;
        unsigned char           * xmit_buf;
@@ -122,8 +121,6 @@ struct specialix_port {
        int                     xmit_cnt;
        wait_queue_head_t       open_wait;
        wait_queue_head_t       close_wait;
-       struct work_struct      tqueue;
-       struct work_struct      tqueue_hangup;
        short                   wakeup_chars;
        short                   break_length;
        unsigned short          closing_wait;
index 45758d5b56ef88f3c2700fb218b55d6b71994b90..feac54e32a12753f25f78eaed9e7c1b7749cc141 100644 (file)
@@ -145,8 +145,7 @@ static struct stlbrd                *stl_brds[STL_MAXBRDS];
  */
 #define        ASYI_TXBUSY     1
 #define        ASYI_TXLOW      2
-#define        ASYI_DCDCHANGE  3
-#define        ASYI_TXFLOWED   4
+#define        ASYI_TXFLOWED   3
 
 /*
  *     Define an array of board names as printable strings. Handy for
@@ -610,6 +609,23 @@ static const struct file_operations        stl_fsiomem = {
 
 static struct class *stallion_class;
 
+static void stl_cd_change(struct stlport *portp)
+{
+       unsigned int oldsigs = portp->sigs;
+
+       if (!portp->tty)
+               return;
+
+       portp->sigs = stl_getsignals(portp);
+
+       if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
+               wake_up_interruptible(&portp->open_wait);
+
+       if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
+               if (portp->flags & ASYNC_CHECK_CD)
+                       tty_hangup(portp->tty);
+}
+
 /*
  *     Check for any arguments passed in on the module load command line.
  */
@@ -1770,41 +1786,6 @@ static int stl_echpci64intr(struct stlbrd *brdp)
 
 /*****************************************************************************/
 
-/*
- *     Service an off-level request for some channel.
- */
-static void stl_offintr(struct work_struct *work)
-{
-       struct stlport          *portp = container_of(work, struct stlport, tqueue);
-       struct tty_struct       *tty;
-       unsigned int            oldsigs;
-
-       pr_debug("stl_offintr(portp=%p)\n", portp);
-
-       if (portp == NULL)
-               return;
-
-       tty = portp->tty;
-       if (tty == NULL)
-               return;
-
-       if (test_bit(ASYI_TXLOW, &portp->istate))
-               tty_wakeup(tty);
-
-       if (test_bit(ASYI_DCDCHANGE, &portp->istate)) {
-               clear_bit(ASYI_DCDCHANGE, &portp->istate);
-               oldsigs = portp->sigs;
-               portp->sigs = stl_getsignals(portp);
-               if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
-                       wake_up_interruptible(&portp->open_wait);
-               if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
-                       if (portp->flags & ASYNC_CHECK_CD)
-                               tty_hangup(tty);        /* FIXME: module removal race here - AKPM */
-       }
-}
-
-/*****************************************************************************/
-
 /*
  *     Initialize all the ports on a panel.
  */
@@ -1840,7 +1821,6 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
                portp->baud_base = STL_BAUDBASE;
                portp->close_delay = STL_CLOSEDELAY;
                portp->closing_wait = 30 * HZ;
-               INIT_WORK(&portp->tqueue, stl_offintr);
                init_waitqueue_head(&portp->open_wait);
                init_waitqueue_head(&portp->close_wait);
                portp->stats.brd = portp->brdnr;
@@ -3530,7 +3510,8 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
        if ((len == 0) || ((len < STL_TXBUFLOW) &&
            (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
                set_bit(ASYI_TXLOW, &portp->istate);
-               schedule_work(&portp->tqueue);
+               if (portp->tty)
+                       tty_wakeup(portp->tty);
        }
 
        if (len == 0) {
@@ -3546,7 +3527,8 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
        } else {
                len = min(len, CD1400_TXFIFOSIZE);
                portp->stats.txtotal += len;
-               stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+               stlen = min_t(unsigned int, len,
+                               (portp->tx.buf + STL_TXBUFSIZE) - tail);
                outb((TDR + portp->uartaddr), ioaddr);
                outsb((ioaddr + EREG_DATA), tail, stlen);
                len -= stlen;
@@ -3599,7 +3581,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
                outb((RDCR + portp->uartaddr), ioaddr);
                len = inb(ioaddr + EREG_DATA);
                if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
-                       len = min(len, sizeof(stl_unwanted));
+                       len = min_t(unsigned int, len, sizeof(stl_unwanted));
                        outb((RDSR + portp->uartaddr), ioaddr);
                        insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
                        portp->stats.rxlost += len;
@@ -3692,8 +3674,7 @@ static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr)
        outb((MISR + portp->uartaddr), ioaddr);
        misr = inb(ioaddr + EREG_DATA);
        if (misr & MISR_DCD) {
-               set_bit(ASYI_DCDCHANGE, &portp->istate);
-               schedule_work(&portp->tqueue);
+               stl_cd_change(portp);
                portp->stats.modem++;
        }
 
@@ -4447,7 +4428,8 @@ static void stl_sc26198txisr(struct stlport *portp)
        if ((len == 0) || ((len < STL_TXBUFLOW) &&
            (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
                set_bit(ASYI_TXLOW, &portp->istate);
-               schedule_work(&portp->tqueue); 
+               if (portp->tty)
+                       tty_wakeup(portp->tty);
        }
 
        if (len == 0) {
@@ -4465,7 +4447,8 @@ static void stl_sc26198txisr(struct stlport *portp)
        } else {
                len = min(len, SC26198_TXFIFOSIZE);
                portp->stats.txtotal += len;
-               stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+               stlen = min_t(unsigned int, len,
+                               (portp->tx.buf + STL_TXBUFSIZE) - tail);
                outb(GTXFIFO, (ioaddr + XP_ADDR));
                outsb((ioaddr + XP_DATA), tail, stlen);
                len -= stlen;
@@ -4506,7 +4489,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
 
        if ((iack & IVR_TYPEMASK) == IVR_RXDATA) {
                if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
-                       len = min(len, sizeof(stl_unwanted));
+                       len = min_t(unsigned int, len, sizeof(stl_unwanted));
                        outb(GRXFIFO, (ioaddr + XP_ADDR));
                        insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
                        portp->stats.rxlost += len;
@@ -4647,8 +4630,7 @@ static void stl_sc26198otherisr(struct stlport *portp, unsigned int iack)
        case CIR_SUBCOS:
                ipr = stl_sc26198getreg(portp, IPR);
                if (ipr & IPR_DCDCHANGE) {
-                       set_bit(ASYI_DCDCHANGE, &portp->istate);
-                       schedule_work(&portp->tqueue); 
+                       stl_cd_change(portp);
                        portp->stats.modem++;
                }
                break;
index 70d9783c732391e593eeb8457302aa4fd8016d64..87c2defdead77ecb50812a5572ce29e6b0c1723e 100644 (file)
@@ -88,8 +88,6 @@ struct vpd_prom {
 
 #define IS_CF_BOARD(board) (board->flags & (SX_CFISA_BOARD | SX_CFPCI_BOARD))
 
-#define SERIAL_TYPE_NORMAL 1
-
 /* The SI processor clock is required to calculate the cc_int_count register
    value for the SI cards. */
 #define SI_PROCESSOR_CLOCK 25000000
index d010ed95ed3b1681bed5cea128625bbaea61a71b..ddc74d1f4f1beb3922c39fa4809a428529a74615 100644 (file)
@@ -85,6 +85,7 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/ioctl.h>
+#include <linux/synclink.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 
 #include <asm/uaccess.h>
 
-#include "linux/synclink.h"
-
 #define RCLRVALUE 0xffff
 
 static MGSL_PARAMS default_params = {
index 64e835f62438d3bb6b629224355403c14681927a..1f954acf2bac49125be4b18f0167eb437ec0cbe0 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/bitops.h>
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
+#include <linux/synclink.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -81,8 +82,6 @@
 #include <asm/types.h>
 #include <asm/uaccess.h>
 
-#include "linux/synclink.h"
-
 #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE))
 #define SYNCLINK_GENERIC_HDLC 1
 #else
@@ -2040,37 +2039,41 @@ static void bh_transmit(struct slgt_info *info)
                tty_wakeup(tty);
 }
 
-static void dsr_change(struct slgt_info *info)
+static void dsr_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT3) {
+               info->signals |= SerialSignal_DSR;
+               info->input_signal_events.dsr_up++;
+       } else {
+               info->signals &= ~SerialSignal_DSR;
+               info->input_signal_events.dsr_down++;
+       }
        DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_DSR);
                return;
        }
        info->icount.dsr++;
-       if (info->signals & SerialSignal_DSR)
-               info->input_signal_events.dsr_up++;
-       else
-               info->input_signal_events.dsr_down++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
 }
 
-static void cts_change(struct slgt_info *info)
+static void cts_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT2) {
+               info->signals |= SerialSignal_CTS;
+               info->input_signal_events.cts_up++;
+       } else {
+               info->signals &= ~SerialSignal_CTS;
+               info->input_signal_events.cts_down++;
+       }
        DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_CTS);
                return;
        }
        info->icount.cts++;
-       if (info->signals & SerialSignal_CTS)
-               info->input_signal_events.cts_up++;
-       else
-               info->input_signal_events.cts_down++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
@@ -2091,20 +2094,21 @@ static void cts_change(struct slgt_info *info)
        }
 }
 
-static void dcd_change(struct slgt_info *info)
+static void dcd_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT1) {
+               info->signals |= SerialSignal_DCD;
+               info->input_signal_events.dcd_up++;
+       } else {
+               info->signals &= ~SerialSignal_DCD;
+               info->input_signal_events.dcd_down++;
+       }
        DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_DCD);
                return;
        }
        info->icount.dcd++;
-       if (info->signals & SerialSignal_DCD) {
-               info->input_signal_events.dcd_up++;
-       } else {
-               info->input_signal_events.dcd_down++;
-       }
 #if SYNCLINK_GENERIC_HDLC
        if (info->netcount) {
                if (info->signals & SerialSignal_DCD)
@@ -2127,20 +2131,21 @@ static void dcd_change(struct slgt_info *info)
        }
 }
 
-static void ri_change(struct slgt_info *info)
+static void ri_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT0) {
+               info->signals |= SerialSignal_RI;
+               info->input_signal_events.ri_up++;
+       } else {
+               info->signals &= ~SerialSignal_RI;
+               info->input_signal_events.ri_down++;
+       }
        DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_RI);
                return;
        }
-       info->icount.dcd++;
-       if (info->signals & SerialSignal_RI) {
-               info->input_signal_events.ri_up++;
-       } else {
-               info->input_signal_events.ri_down++;
-       }
+       info->icount.rng++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
@@ -2191,13 +2196,13 @@ static void isr_serial(struct slgt_info *info)
        }
 
        if (status & IRQ_DSR)
-               dsr_change(info);
+               dsr_change(info, status);
        if (status & IRQ_CTS)
-               cts_change(info);
+               cts_change(info, status);
        if (status & IRQ_DCD)
-               dcd_change(info);
+               dcd_change(info, status);
        if (status & IRQ_RI)
-               ri_change(info);
+               ri_change(info, status);
 }
 
 static void isr_rdma(struct slgt_info *info)
index c63013b2fc366487a781b925e7738175e7ccee7a..f3e7807f78d98781d903ea8075a970e18c881033 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/termios.h>
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
+#include <linux/synclink.h>
 
 #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE))
 #define SYNCLINK_GENERIC_HDLC 1
@@ -80,8 +81,6 @@
 
 #include <asm/uaccess.h>
 
-#include "linux/synclink.h"
-
 static MGSL_PARAMS default_params = {
        MGSL_MODE_HDLC,                 /* unsigned long mode */
        0,                              /* unsigned char loopback; */
index c88424a0c89b60d28d3805895e6ee973710b7d8c..a5d8bcb40000df912d43cb9ad4a8cc9c7453642c 100644 (file)
@@ -1031,18 +1031,13 @@ void tpm_remove_hardware(struct device *dev)
 
        spin_unlock(&driver_lock);
 
-       dev_set_drvdata(dev, NULL);
        misc_deregister(&chip->vendor.miscdev);
-       kfree(chip->vendor.miscdev.name);
 
        sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
        tpm_bios_log_teardown(chip->bios_dir);
 
-       clear_bit(chip->dev_num, dev_mask);
-
-       kfree(chip);
-
-       put_device(dev);
+       /* write it this way to be explicit (chip->dev == dev) */
+       put_device(chip->dev);
 }
 EXPORT_SYMBOL_GPL(tpm_remove_hardware);
 
@@ -1082,6 +1077,26 @@ int tpm_pm_resume(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(tpm_pm_resume);
 
+/*
+ * Once all references to platform device are down to 0,
+ * release all allocated structures.
+ * In case vendor provided release function,
+ * call it too.
+ */
+static void tpm_dev_release(struct device *dev)
+{
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+
+       if (chip->vendor.release)
+               chip->vendor.release(dev);
+
+       chip->release(dev);
+
+       clear_bit(chip->dev_num, dev_mask);
+       kfree(chip->vendor.miscdev.name);
+       kfree(chip);
+}
+
 /*
  * Called from tpm_<specific>.c probe function only for devices 
  * the driver has determined it should claim.  Prior to calling
@@ -1136,23 +1151,21 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
 
        chip->vendor.miscdev.parent = dev;
        chip->dev = get_device(dev);
+       chip->release = dev->release;
+       dev->release = tpm_dev_release;
+       dev_set_drvdata(dev, chip);
 
        if (misc_register(&chip->vendor.miscdev)) {
                dev_err(chip->dev,
                        "unable to misc_register %s, minor %d\n",
                        chip->vendor.miscdev.name,
                        chip->vendor.miscdev.minor);
-               put_device(dev);
-               clear_bit(chip->dev_num, dev_mask);
-               kfree(chip);
-               kfree(devname);
+               put_device(chip->dev);
                return NULL;
        }
 
        spin_lock(&driver_lock);
 
-       dev_set_drvdata(dev, chip);
-
        list_add(&chip->list, &tpm_chip_list);
 
        spin_unlock(&driver_lock);
@@ -1160,10 +1173,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
        if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
                list_del(&chip->list);
                misc_deregister(&chip->vendor.miscdev);
-               put_device(dev);
-               clear_bit(chip->dev_num, dev_mask);
-               kfree(chip);
-               kfree(devname);
+               put_device(chip->dev);
                return NULL;
        }
 
index d15ccddc92ebc6080762cb3c22d019d7f16c923a..e885148b4cfbd0b177f77b87e6e629511db16983 100644 (file)
@@ -74,6 +74,7 @@ struct tpm_vendor_specific {
        int (*send) (struct tpm_chip *, u8 *, size_t);
        void (*cancel) (struct tpm_chip *);
        u8 (*status) (struct tpm_chip *);
+       void (*release) (struct device *);
        struct miscdevice miscdev;
        struct attribute_group *attr_group;
        struct list_head list;
@@ -106,6 +107,7 @@ struct tpm_chip {
        struct dentry **bios_dir;
 
        struct list_head list;
+       void (*release) (struct device *);
 };
 
 #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
index 967002a5a1e56dae86010e8af334a2b814fe9a4c..726ee8a0277fe6fbefebd58e93c28da5713d9f9a 100644 (file)
@@ -611,7 +611,7 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
        }
 }
 
-static struct pnp_driver tpm_inf_pnp = {
+static struct pnp_driver tpm_inf_pnp_driver = {
        .name = "tpm_inf_pnp",
        .driver = {
                .owner = THIS_MODULE,
@@ -625,12 +625,12 @@ static struct pnp_driver tpm_inf_pnp = {
 
 static int __init init_inf(void)
 {
-       return pnp_register_driver(&tpm_inf_pnp);
+       return pnp_register_driver(&tpm_inf_pnp_driver);
 }
 
 static void __exit cleanup_inf(void)
 {
-       pnp_unregister_driver(&tpm_inf_pnp);
+       pnp_unregister_driver(&tpm_inf_pnp_driver);
 }
 
 module_init(init_inf);
index f36fecd3fd264a67cf7d66b2fd8e74369a38f406..79c86c47947f4da921051be399b028f176f18ad9 100644 (file)
@@ -138,7 +138,7 @@ EXPORT_SYMBOL(tty_mutex);
 extern struct tty_driver *ptm_driver;  /* Unix98 pty masters; for /dev/ptmx */
 extern int pty_limit;          /* Config limit on Unix98 ptys */
 static DEFINE_IDR(allocated_ptys);
-static DECLARE_MUTEX(allocated_ptys_lock);
+static DEFINE_MUTEX(allocated_ptys_lock);
 static int ptmx_open(struct inode *, struct file *);
 #endif
 
@@ -2571,9 +2571,9 @@ static void release_dev(struct file * filp)
 #ifdef CONFIG_UNIX98_PTYS
        /* Make this pty number available for reallocation */
        if (devpts) {
-               down(&allocated_ptys_lock);
+               mutex_lock(&allocated_ptys_lock);
                idr_remove(&allocated_ptys, idx);
-               up(&allocated_ptys_lock);
+               mutex_unlock(&allocated_ptys_lock);
        }
 #endif
 
@@ -2737,24 +2737,24 @@ static int ptmx_open(struct inode * inode, struct file * filp)
        nonseekable_open(inode, filp);
 
        /* find a device that is not in use. */
-       down(&allocated_ptys_lock);
+       mutex_lock(&allocated_ptys_lock);
        if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
-               up(&allocated_ptys_lock);
+               mutex_unlock(&allocated_ptys_lock);
                return -ENOMEM;
        }
        idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
        if (idr_ret < 0) {
-               up(&allocated_ptys_lock);
+               mutex_unlock(&allocated_ptys_lock);
                if (idr_ret == -EAGAIN)
                        return -ENOMEM;
                return -EIO;
        }
        if (index >= pty_limit) {
                idr_remove(&allocated_ptys, index);
-               up(&allocated_ptys_lock);
+               mutex_unlock(&allocated_ptys_lock);
                return -EIO;
        }
-       up(&allocated_ptys_lock);
+       mutex_unlock(&allocated_ptys_lock);
 
        mutex_lock(&tty_mutex);
        retval = init_dev(ptm_driver, index, &tty);
@@ -2781,9 +2781,9 @@ out1:
        release_dev(filp);
        return retval;
 out:
-       down(&allocated_ptys_lock);
+       mutex_lock(&allocated_ptys_lock);
        idr_remove(&allocated_ptys, index);
-       up(&allocated_ptys_lock);
+       mutex_unlock(&allocated_ptys_lock);
        return retval;
 }
 #endif
@@ -3721,7 +3721,6 @@ static void initialize_tty_struct(struct tty_struct *tty)
        tty->buf.head = tty->buf.tail = NULL;
        tty_buffer_init(tty);
        INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
-       init_MUTEX(&tty->buf.pty_sem);
        mutex_init(&tty->termios_mutex);
        init_waitqueue_head(&tty->write_wait);
        init_waitqueue_head(&tty->read_wait);
@@ -4048,10 +4047,6 @@ void __init console_init(void)
        }
 }
 
-#ifdef CONFIG_VT
-extern int vty_init(void);
-#endif
-
 static int __init tty_class_init(void)
 {
        tty_class = class_create(THIS_MODULE, "tty");
index 7a5badfb7d846e00d85dbbd2c082461264b7a660..367be917506117b08d2407b7f74beb55432701d4 100644 (file)
@@ -2400,13 +2400,15 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
 {
        struct vc_data *vc = vc_cons[fg_console].d;
        unsigned char c;
-       static unsigned long printing;
+       static DEFINE_SPINLOCK(printing_lock);
        const ushort *start;
        ushort cnt = 0;
        ushort myx;
 
        /* console busy or not yet initialized */
-       if (!printable || test_and_set_bit(0, &printing))
+       if (!printable)
+               return;
+       if (!spin_trylock(&printing_lock))
                return;
 
        if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
@@ -2481,7 +2483,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
        notify_update(vc);
 
 quit:
-       clear_bit(0, &printing);
+       spin_unlock(&printing_lock);
 }
 
 static struct tty_driver *vt_console_device(struct console *c, int *index)
index c46b7c219ee92987b59386adbaa791b167aa28df..a703deffb7954cd3a1fd4831adaa48403b1b06ba 100644 (file)
@@ -5,6 +5,7 @@
 menuconfig DMADEVICES
        bool "DMA Engine support"
        depends on (PCI && X86) || ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
+       depends on !HIGHMEM64G
        help
          DMA engines can do asynchronous data transfers without
          involving the host CPU.  Currently, this framework can be
index bcf52df303390dbf775ea91cd9ab9e714f3f8178..29965231b9127e6e9e658997f26b72ffb69c4d3c 100644 (file)
@@ -473,20 +473,22 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
 {
        struct dma_device *dev = chan->device;
        struct dma_async_tx_descriptor *tx;
-       dma_addr_t addr;
+       dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
        int cpu;
 
-       tx = dev->device_prep_dma_memcpy(chan, len, 0);
-       if (!tx)
+       dma_src = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
+       dma_dest = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE);
+       tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0);
+
+       if (!tx) {
+               dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE);
+               dma_unmap_single(dev->dev, dma_dest, len, DMA_FROM_DEVICE);
                return -ENOMEM;
+       }
 
        tx->ack = 1;
        tx->callback = NULL;
-       addr = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
-       tx->tx_set_src(addr, tx, 0);
-       addr = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE);
-       tx->tx_set_dest(addr, tx, 0);
        cookie = tx->tx_submit(tx);
 
        cpu = get_cpu();
@@ -517,20 +519,22 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
 {
        struct dma_device *dev = chan->device;
        struct dma_async_tx_descriptor *tx;
-       dma_addr_t addr;
+       dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
        int cpu;
 
-       tx = dev->device_prep_dma_memcpy(chan, len, 0);
-       if (!tx)
+       dma_src = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
+       dma_dest = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE);
+       tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0);
+
+       if (!tx) {
+               dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE);
+               dma_unmap_page(dev->dev, dma_dest, len, DMA_FROM_DEVICE);
                return -ENOMEM;
+       }
 
        tx->ack = 1;
        tx->callback = NULL;
-       addr = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
-       tx->tx_set_src(addr, tx, 0);
-       addr = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE);
-       tx->tx_set_dest(addr, tx, 0);
        cookie = tx->tx_submit(tx);
 
        cpu = get_cpu();
@@ -563,20 +567,23 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
 {
        struct dma_device *dev = chan->device;
        struct dma_async_tx_descriptor *tx;
-       dma_addr_t addr;
+       dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
        int cpu;
 
-       tx = dev->device_prep_dma_memcpy(chan, len, 0);
-       if (!tx)
+       dma_src = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
+       dma_dest = dma_map_page(dev->dev, dest_pg, dest_off, len,
+                               DMA_FROM_DEVICE);
+       tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0);
+
+       if (!tx) {
+               dma_unmap_page(dev->dev, dma_src, len, DMA_TO_DEVICE);
+               dma_unmap_page(dev->dev, dma_dest, len, DMA_FROM_DEVICE);
                return -ENOMEM;
+       }
 
        tx->ack = 1;
        tx->callback = NULL;
-       addr = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
-       tx->tx_set_src(addr, tx, 0);
-       addr = dma_map_page(dev->dev, dest_pg, dest_off, len, DMA_FROM_DEVICE);
-       tx->tx_set_dest(addr, tx, 0);
        cookie = tx->tx_submit(tx);
 
        cpu = get_cpu();
index 45e7b4666c7b3c5197eeaa0c256dcf76860a2161..dff38accc5c1df47193a73b4fb81e467012d80b6 100644 (file)
@@ -159,20 +159,6 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
        return device->common.chancnt;
 }
 
-static void ioat_set_src(dma_addr_t addr,
-                        struct dma_async_tx_descriptor *tx,
-                        int index)
-{
-       tx_to_ioat_desc(tx)->src = addr;
-}
-
-static void ioat_set_dest(dma_addr_t addr,
-                         struct dma_async_tx_descriptor *tx,
-                         int index)
-{
-       tx_to_ioat_desc(tx)->dst = addr;
-}
-
 /**
  * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended
  *                                 descriptors to hw
@@ -415,8 +401,6 @@ static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
 
        memset(desc, 0, sizeof(*desc));
        dma_async_tx_descriptor_init(&desc_sw->async_tx, &ioat_chan->common);
-       desc_sw->async_tx.tx_set_src = ioat_set_src;
-       desc_sw->async_tx.tx_set_dest = ioat_set_dest;
        switch (ioat_chan->device->version) {
        case IOAT_VER_1_2:
                desc_sw->async_tx.tx_submit = ioat1_tx_submit;
@@ -714,8 +698,10 @@ static struct ioat_desc_sw *ioat_dma_get_next_descriptor(
 
 static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
                                                struct dma_chan *chan,
+                                               dma_addr_t dma_dest,
+                                               dma_addr_t dma_src,
                                                size_t len,
-                                               int int_en)
+                                               unsigned long flags)
 {
        struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
        struct ioat_desc_sw *new;
@@ -726,6 +712,8 @@ static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
 
        if (new) {
                new->len = len;
+               new->dst = dma_dest;
+               new->src = dma_src;
                return &new->async_tx;
        } else
                return NULL;
@@ -733,8 +721,10 @@ static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
 
 static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy(
                                                struct dma_chan *chan,
+                                               dma_addr_t dma_dest,
+                                               dma_addr_t dma_src,
                                                size_t len,
-                                               int int_en)
+                                               unsigned long flags)
 {
        struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
        struct ioat_desc_sw *new;
@@ -749,6 +739,8 @@ static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy(
 
        if (new) {
                new->len = len;
+               new->dst = dma_dest;
+               new->src = dma_src;
                return &new->async_tx;
        } else
                return NULL;
@@ -1045,7 +1037,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
        u8 *dest;
        struct dma_chan *dma_chan;
        struct dma_async_tx_descriptor *tx;
-       dma_addr_t addr;
+       dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
        int err = 0;
 
@@ -1073,7 +1065,12 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
                goto out;
        }
 
-       tx = device->common.device_prep_dma_memcpy(dma_chan, IOAT_TEST_SIZE, 0);
+       dma_src = dma_map_single(dma_chan->device->dev, src, IOAT_TEST_SIZE,
+                                DMA_TO_DEVICE);
+       dma_dest = dma_map_single(dma_chan->device->dev, dest, IOAT_TEST_SIZE,
+                                 DMA_FROM_DEVICE);
+       tx = device->common.device_prep_dma_memcpy(dma_chan, dma_dest, dma_src,
+                                                  IOAT_TEST_SIZE, 0);
        if (!tx) {
                dev_err(&device->pdev->dev,
                        "Self-test prep failed, disabling\n");
@@ -1082,12 +1079,6 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
        }
 
        async_tx_ack(tx);
-       addr = dma_map_single(dma_chan->device->dev, src, IOAT_TEST_SIZE,
-                             DMA_TO_DEVICE);
-       tx->tx_set_src(addr, tx, 0);
-       addr = dma_map_single(dma_chan->device->dev, dest, IOAT_TEST_SIZE,
-                             DMA_FROM_DEVICE);
-       tx->tx_set_dest(addr, tx, 0);
        tx->callback = ioat_dma_test_callback;
        tx->callback_param = (void *)0x8086;
        cookie = tx->tx_submit(tx);
index e5c62b75f36f1adefe418e28d6089fc83dc4f6f9..3986d54492bde18d2b0d45d2e64a449dac5af227 100644 (file)
@@ -284,7 +284,7 @@ iop_adma_alloc_slots(struct iop_adma_chan *iop_chan, int num_slots,
                        int slots_per_op)
 {
        struct iop_adma_desc_slot *iter, *_iter, *alloc_start = NULL;
-       struct list_head chain = LIST_HEAD_INIT(chain);
+       LIST_HEAD(chain);
        int slots_found, retry = 0;
 
        /* start search from the last allocated descrtiptor
@@ -443,17 +443,6 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx)
        return cookie;
 }
 
-static void
-iop_adma_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
-       int index)
-{
-       struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
-       struct iop_adma_chan *iop_chan = to_iop_adma_chan(tx->chan);
-
-       /* to do: support transfers lengths > IOP_ADMA_MAX_BYTE_COUNT */
-       iop_desc_set_dest_addr(sw_desc->group_head, iop_chan, addr);
-}
-
 static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan);
 static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan);
 
@@ -486,7 +475,6 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan)
 
                dma_async_tx_descriptor_init(&slot->async_tx, chan);
                slot->async_tx.tx_submit = iop_adma_tx_submit;
-               slot->async_tx.tx_set_dest = iop_adma_set_dest;
                INIT_LIST_HEAD(&slot->chain_node);
                INIT_LIST_HEAD(&slot->slot_node);
                INIT_LIST_HEAD(&slot->async_tx.tx_list);
@@ -547,18 +535,9 @@ iop_adma_prep_dma_interrupt(struct dma_chan *chan)
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
 
-static void
-iop_adma_memcpy_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
-       int index)
-{
-       struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
-       struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
-
-       iop_desc_set_memcpy_src_addr(grp_start, addr);
-}
-
 static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_memcpy(struct dma_chan *chan, size_t len, int int_en)
+iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
+                        dma_addr_t dma_src, size_t len, unsigned long flags)
 {
        struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
        struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -576,11 +555,12 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, size_t len, int int_en)
        sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
        if (sw_desc) {
                grp_start = sw_desc->group_head;
-               iop_desc_init_memcpy(grp_start, int_en);
+               iop_desc_init_memcpy(grp_start, flags);
                iop_desc_set_byte_count(grp_start, iop_chan, len);
+               iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
+               iop_desc_set_memcpy_src_addr(grp_start, dma_src);
                sw_desc->unmap_src_cnt = 1;
                sw_desc->unmap_len = len;
-               sw_desc->async_tx.tx_set_src = iop_adma_memcpy_set_src;
        }
        spin_unlock_bh(&iop_chan->lock);
 
@@ -588,8 +568,8 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, size_t len, int int_en)
 }
 
 static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_memset(struct dma_chan *chan, int value, size_t len,
-       int int_en)
+iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest,
+                        int value, size_t len, unsigned long flags)
 {
        struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
        struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -607,9 +587,10 @@ iop_adma_prep_dma_memset(struct dma_chan *chan, int value, size_t len,
        sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
        if (sw_desc) {
                grp_start = sw_desc->group_head;
-               iop_desc_init_memset(grp_start, int_en);
+               iop_desc_init_memset(grp_start, flags);
                iop_desc_set_byte_count(grp_start, iop_chan, len);
                iop_desc_set_block_fill_val(grp_start, value);
+               iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
                sw_desc->unmap_src_cnt = 1;
                sw_desc->unmap_len = len;
        }
@@ -618,19 +599,10 @@ iop_adma_prep_dma_memset(struct dma_chan *chan, int value, size_t len,
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
 
-static void
-iop_adma_xor_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
-       int index)
-{
-       struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
-       struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
-
-       iop_desc_set_xor_src_addr(grp_start, index, addr);
-}
-
 static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_xor(struct dma_chan *chan, unsigned int src_cnt, size_t len,
-       int int_en)
+iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest,
+                     dma_addr_t *dma_src, unsigned int src_cnt, size_t len,
+                     unsigned long flags)
 {
        struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
        struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -641,39 +613,32 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, unsigned int src_cnt, size_t len,
        BUG_ON(unlikely(len > IOP_ADMA_XOR_MAX_BYTE_COUNT));
 
        dev_dbg(iop_chan->device->common.dev,
-               "%s src_cnt: %d len: %u int_en: %d\n",
-               __FUNCTION__, src_cnt, len, int_en);
+               "%s src_cnt: %d len: %u flags: %lx\n",
+               __FUNCTION__, src_cnt, len, flags);
 
        spin_lock_bh(&iop_chan->lock);
        slot_cnt = iop_chan_xor_slot_count(len, src_cnt, &slots_per_op);
        sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
        if (sw_desc) {
                grp_start = sw_desc->group_head;
-               iop_desc_init_xor(grp_start, src_cnt, int_en);
+               iop_desc_init_xor(grp_start, src_cnt, flags);
                iop_desc_set_byte_count(grp_start, iop_chan, len);
+               iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
                sw_desc->unmap_src_cnt = src_cnt;
                sw_desc->unmap_len = len;
-               sw_desc->async_tx.tx_set_src = iop_adma_xor_set_src;
+               while (src_cnt--)
+                       iop_desc_set_xor_src_addr(grp_start, src_cnt,
+                                                 dma_src[src_cnt]);
        }
        spin_unlock_bh(&iop_chan->lock);
 
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
 
-static void
-iop_adma_xor_zero_sum_set_src(dma_addr_t addr,
-                               struct dma_async_tx_descriptor *tx,
-                               int index)
-{
-       struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
-       struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
-
-       iop_desc_set_zero_sum_src_addr(grp_start, index, addr);
-}
-
 static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_zero_sum(struct dma_chan *chan, unsigned int src_cnt,
-       size_t len, u32 *result, int int_en)
+iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src,
+                          unsigned int src_cnt, size_t len, u32 *result,
+                          unsigned long flags)
 {
        struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
        struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -690,14 +655,16 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, unsigned int src_cnt,
        sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
        if (sw_desc) {
                grp_start = sw_desc->group_head;
-               iop_desc_init_zero_sum(grp_start, src_cnt, int_en);
+               iop_desc_init_zero_sum(grp_start, src_cnt, flags);
                iop_desc_set_zero_sum_byte_count(grp_start, len);
                grp_start->xor_check_result = result;
                pr_debug("\t%s: grp_start->xor_check_result: %p\n",
                        __FUNCTION__, grp_start->xor_check_result);
                sw_desc->unmap_src_cnt = src_cnt;
                sw_desc->unmap_len = len;
-               sw_desc->async_tx.tx_set_src = iop_adma_xor_zero_sum_set_src;
+               while (src_cnt--)
+                       iop_desc_set_zero_sum_src_addr(grp_start, src_cnt,
+                                                      dma_src[src_cnt]);
        }
        spin_unlock_bh(&iop_chan->lock);
 
@@ -882,13 +849,12 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device)
                goto out;
        }
 
-       tx = iop_adma_prep_dma_memcpy(dma_chan, IOP_ADMA_TEST_SIZE, 1);
        dest_dma = dma_map_single(dma_chan->device->dev, dest,
                                IOP_ADMA_TEST_SIZE, DMA_FROM_DEVICE);
-       iop_adma_set_dest(dest_dma, tx, 0);
        src_dma = dma_map_single(dma_chan->device->dev, src,
                                IOP_ADMA_TEST_SIZE, DMA_TO_DEVICE);
-       iop_adma_memcpy_set_src(src_dma, tx, 0);
+       tx = iop_adma_prep_dma_memcpy(dma_chan, dest_dma, src_dma,
+                                     IOP_ADMA_TEST_SIZE, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
@@ -929,6 +895,7 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
        struct page *dest;
        struct page *xor_srcs[IOP_ADMA_NUM_SRC_TEST];
        struct page *zero_sum_srcs[IOP_ADMA_NUM_SRC_TEST + 1];
+       dma_addr_t dma_srcs[IOP_ADMA_NUM_SRC_TEST + 1];
        dma_addr_t dma_addr, dest_dma;
        struct dma_async_tx_descriptor *tx;
        struct dma_chan *dma_chan;
@@ -981,17 +948,13 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
        }
 
        /* test xor */
-       tx = iop_adma_prep_dma_xor(dma_chan, IOP_ADMA_NUM_SRC_TEST,
-                               PAGE_SIZE, 1);
        dest_dma = dma_map_page(dma_chan->device->dev, dest, 0,
                                PAGE_SIZE, DMA_FROM_DEVICE);
-       iop_adma_set_dest(dest_dma, tx, 0);
-
-       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++) {
-               dma_addr = dma_map_page(dma_chan->device->dev, xor_srcs[i], 0,
-                       PAGE_SIZE, DMA_TO_DEVICE);
-               iop_adma_xor_set_src(dma_addr, tx, i);
-       }
+       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++)
+               dma_srcs[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i],
+                                          0, PAGE_SIZE, DMA_TO_DEVICE);
+       tx = iop_adma_prep_dma_xor(dma_chan, dest_dma, dma_srcs,
+                                  IOP_ADMA_NUM_SRC_TEST, PAGE_SIZE, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
@@ -1032,13 +995,13 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
 
        zero_sum_result = 1;
 
-       tx = iop_adma_prep_dma_zero_sum(dma_chan, IOP_ADMA_NUM_SRC_TEST + 1,
-               PAGE_SIZE, &zero_sum_result, 1);
-       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++) {
-               dma_addr = dma_map_page(dma_chan->device->dev, zero_sum_srcs[i],
-                       0, PAGE_SIZE, DMA_TO_DEVICE);
-               iop_adma_xor_zero_sum_set_src(dma_addr, tx, i);
-       }
+       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++)
+               dma_srcs[i] = dma_map_page(dma_chan->device->dev,
+                                          zero_sum_srcs[i], 0, PAGE_SIZE,
+                                          DMA_TO_DEVICE);
+       tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs,
+                                       IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE,
+                                       &zero_sum_result, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
@@ -1060,10 +1023,9 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
        }
 
        /* test memset */
-       tx = iop_adma_prep_dma_memset(dma_chan, 0, PAGE_SIZE, 1);
        dma_addr = dma_map_page(dma_chan->device->dev, dest, 0,
                        PAGE_SIZE, DMA_FROM_DEVICE);
-       iop_adma_set_dest(dma_addr, tx, 0);
+       tx = iop_adma_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
@@ -1089,13 +1051,13 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
 
        /* test for non-zero parity sum */
        zero_sum_result = 0;
-       tx = iop_adma_prep_dma_zero_sum(dma_chan, IOP_ADMA_NUM_SRC_TEST + 1,
-               PAGE_SIZE, &zero_sum_result, 1);
-       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++) {
-               dma_addr = dma_map_page(dma_chan->device->dev, zero_sum_srcs[i],
-                       0, PAGE_SIZE, DMA_TO_DEVICE);
-               iop_adma_xor_zero_sum_set_src(dma_addr, tx, i);
-       }
+       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++)
+               dma_srcs[i] = dma_map_page(dma_chan->device->dev,
+                                          zero_sum_srcs[i], 0, PAGE_SIZE,
+                                          DMA_TO_DEVICE);
+       tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs,
+                                       IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE,
+                                       &zero_sum_result, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
index 98b6b4fb42577615447648d0cdbb3a3a7a33ca98..2b382990fe58772238eabd8e29b2485b95981778 100644 (file)
@@ -97,7 +97,7 @@ config EDAC_I82975X
 
 config EDAC_I3000
        tristate "Intel 3000/3010"
-       depends on EDAC_MM_EDAC && PCI && X86_32
+       depends on EDAC_MM_EDAC && PCI && X86
        help
          Support for error detection and correction on the Intel
          3000 and 3010 server chipsets.
@@ -123,6 +123,20 @@ config EDAC_I5000
          Support for error detection and correction the Intel
          Greekcreek/Blackford chipsets.
 
+config EDAC_MPC85XX
+       tristate "Freescale MPC85xx"
+       depends on EDAC_MM_EDAC && FSL_SOC && MPC85xx
+       help
+         Support for error detection and correction on the Freescale
+         MPC8560, MPC8540, MPC8548
+
+config EDAC_MV64X60
+       tristate "Marvell MV64x60"
+       depends on EDAC_MM_EDAC && MV64X60
+       help
+         Support for error detection and correction on the Marvell
+         MV64360 and MV64460 chipsets.
+
 config EDAC_PASEMI
        tristate "PA Semi PWRficient"
        depends on EDAC_MM_EDAC && PCI
@@ -131,5 +145,12 @@ config EDAC_PASEMI
          Support for error detection and correction on PA Semi
          PWRficient.
 
+config EDAC_CELL
+       tristate "Cell Broadband Engine memory controller"
+       depends on EDAC_MM_EDAC && PPC_CELL_NATIVE
+       help
+         Support for error detection and correction on the
+         Cell Broadband Engine internal memory controller
+         on platform without a hypervisor
 
 endif # EDAC
index 02c09f0ff1578e6849e56629c5ea7a62b9a8ebfe..83807731d4a9782f673e7dd46ad9d6af183d4193 100644 (file)
@@ -28,4 +28,7 @@ obj-$(CONFIG_EDAC_I3000)              += i3000_edac.o
 obj-$(CONFIG_EDAC_I82860)              += i82860_edac.o
 obj-$(CONFIG_EDAC_R82600)              += r82600_edac.o
 obj-$(CONFIG_EDAC_PASEMI)              += pasemi_edac.o
+obj-$(CONFIG_EDAC_MPC85XX)             += mpc85xx_edac.o
+obj-$(CONFIG_EDAC_MV64X60)             += mv64x60_edac.o
+obj-$(CONFIG_EDAC_CELL)                        += cell_edac.o
 
diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c
new file mode 100644 (file)
index 0000000..b54112f
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Cell MIC driver for ECC counting
+ *
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ *                <benh@kernel.crashing.org>
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ */
+#undef DEBUG
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/stop_machine.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/cell-regs.h>
+
+#include "edac_core.h"
+
+struct cell_edac_priv
+{
+       struct cbe_mic_tm_regs __iomem  *regs;
+       int                             node;
+       int                             chanmask;
+#ifdef DEBUG
+       u64                             prev_fir;
+#endif
+};
+
+static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
+{
+       struct cell_edac_priv           *priv = mci->pvt_info;
+       struct csrow_info               *csrow = &mci->csrows[0];
+       unsigned long                   address, pfn, offset;
+
+       dev_dbg(mci->dev, "ECC CE err on node %d, channel %d, ar = 0x%016lx\n",
+               priv->node, chan, ar);
+
+       /* Address decoding is likely a bit bogus, to dbl check */
+       address = (ar & 0xffffffffe0000000ul) >> 29;
+       if (priv->chanmask == 0x3)
+               address = (address << 1) | chan;
+       pfn = address >> PAGE_SHIFT;
+       offset = address & ~PAGE_MASK;
+
+       /* TODO: Decoding of the error addresss */
+       edac_mc_handle_ce(mci, csrow->first_page + pfn, offset,
+                         0, 0, chan, "");
+}
+
+static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
+{
+       struct cell_edac_priv           *priv = mci->pvt_info;
+       struct csrow_info               *csrow = &mci->csrows[0];
+       unsigned long                   address, pfn, offset;
+
+       dev_dbg(mci->dev, "ECC UE err on node %d, channel %d, ar = 0x%016lx\n",
+               priv->node, chan, ar);
+
+       /* Address decoding is likely a bit bogus, to dbl check */
+       address = (ar & 0xffffffffe0000000ul) >> 29;
+       if (priv->chanmask == 0x3)
+               address = (address << 1) | chan;
+       pfn = address >> PAGE_SHIFT;
+       offset = address & ~PAGE_MASK;
+
+       /* TODO: Decoding of the error addresss */
+       edac_mc_handle_ue(mci, csrow->first_page + pfn, offset, 0, "");
+}
+
+static void cell_edac_check(struct mem_ctl_info *mci)
+{
+       struct cell_edac_priv           *priv = mci->pvt_info;
+       u64                             fir, addreg, clear = 0;
+
+       fir = in_be64(&priv->regs->mic_fir);
+#ifdef DEBUG
+       if (fir != priv->prev_fir) {
+               dev_dbg(mci->dev, "fir change : 0x%016lx\n", fir);
+               priv->prev_fir = fir;
+       }
+#endif
+       if ((priv->chanmask & 0x1) && (fir & CBE_MIC_FIR_ECC_SINGLE_0_ERR)) {
+               addreg = in_be64(&priv->regs->mic_df_ecc_address_0);
+               clear |= CBE_MIC_FIR_ECC_SINGLE_0_RESET;
+               cell_edac_count_ce(mci, 0, addreg);
+       }
+       if ((priv->chanmask & 0x2) && (fir & CBE_MIC_FIR_ECC_SINGLE_1_ERR)) {
+               addreg = in_be64(&priv->regs->mic_df_ecc_address_1);
+               clear |= CBE_MIC_FIR_ECC_SINGLE_1_RESET;
+               cell_edac_count_ce(mci, 1, addreg);
+       }
+       if ((priv->chanmask & 0x1) && (fir & CBE_MIC_FIR_ECC_MULTI_0_ERR)) {
+               addreg = in_be64(&priv->regs->mic_df_ecc_address_0);
+               clear |= CBE_MIC_FIR_ECC_MULTI_0_RESET;
+               cell_edac_count_ue(mci, 0, addreg);
+       }
+       if ((priv->chanmask & 0x2) && (fir & CBE_MIC_FIR_ECC_MULTI_1_ERR)) {
+               addreg = in_be64(&priv->regs->mic_df_ecc_address_1);
+               clear |= CBE_MIC_FIR_ECC_MULTI_1_RESET;
+               cell_edac_count_ue(mci, 1, addreg);
+       }
+
+       /* The procedure for clearing FIR bits is a bit ... weird */
+       if (clear) {
+               fir &= ~(CBE_MIC_FIR_ECC_ERR_MASK | CBE_MIC_FIR_ECC_SET_MASK);
+               fir |= CBE_MIC_FIR_ECC_RESET_MASK;
+               fir &= ~clear;
+               out_be64(&priv->regs->mic_fir, fir);
+               (void)in_be64(&priv->regs->mic_fir);
+
+               mb();   /* sync up */
+#ifdef DEBUG
+               fir = in_be64(&priv->regs->mic_fir);
+               dev_dbg(mci->dev, "fir clear  : 0x%016lx\n", fir);
+#endif
+       }
+}
+
+static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
+{
+       struct csrow_info               *csrow = &mci->csrows[0];
+       struct cell_edac_priv           *priv = mci->pvt_info;
+       struct device_node              *np;
+
+       for (np = NULL;
+            (np = of_find_node_by_name(np, "memory")) != NULL;) {
+               struct resource r;
+
+               /* We "know" that the Cell firmware only creates one entry
+                * in the "memory" nodes. If that changes, this code will
+                * need to be adapted.
+                */
+               if (of_address_to_resource(np, 0, &r))
+                       continue;
+               if (of_node_to_nid(np) != priv->node)
+                       continue;
+               csrow->first_page = r.start >> PAGE_SHIFT;
+               csrow->nr_pages = (r.end - r.start + 1) >> PAGE_SHIFT;
+               csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
+               csrow->mtype = MEM_XDR;
+               csrow->edac_mode = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+               dev_dbg(mci->dev,
+                       "Initialized on node %d, chanmask=0x%x,"
+                       " first_page=0x%lx, nr_pages=0x%x\n",
+                       priv->node, priv->chanmask,
+                       csrow->first_page, csrow->nr_pages);
+               break;
+       }
+}
+
+static int __devinit cell_edac_probe(struct platform_device *pdev)
+{
+       struct cbe_mic_tm_regs __iomem  *regs;
+       struct mem_ctl_info             *mci;
+       struct cell_edac_priv           *priv;
+       u64                             reg;
+       int                             rc, chanmask;
+
+       regs = cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(pdev->id));
+       if (regs == NULL)
+               return -ENODEV;
+
+       /* Get channel population */
+       reg = in_be64(&regs->mic_mnt_cfg);
+       dev_dbg(&pdev->dev, "MIC_MNT_CFG = 0x%016lx\n", reg);
+       chanmask = 0;
+       if (reg & CBE_MIC_MNT_CFG_CHAN_0_POP)
+               chanmask |= 0x1;
+       if (reg & CBE_MIC_MNT_CFG_CHAN_1_POP)
+               chanmask |= 0x2;
+       if (chanmask == 0) {
+               dev_warn(&pdev->dev,
+                        "Yuck ! No channel populated ? Aborting !\n");
+               return -ENODEV;
+       }
+       dev_dbg(&pdev->dev, "Initial FIR = 0x%016lx\n",
+               in_be64(&regs->mic_fir));
+
+       /* Allocate & init EDAC MC data structure */
+       mci = edac_mc_alloc(sizeof(struct cell_edac_priv), 1,
+                           chanmask == 3 ? 2 : 1, pdev->id);
+       if (mci == NULL)
+               return -ENOMEM;
+       priv = mci->pvt_info;
+       priv->regs = regs;
+       priv->node = pdev->id;
+       priv->chanmask = chanmask;
+       mci->dev = &pdev->dev;
+       mci->mtype_cap = MEM_FLAG_XDR;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+       mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+       mci->mod_name = "cell_edac";
+       mci->ctl_name = "MIC";
+       mci->dev_name = pdev->dev.bus_id;
+       mci->edac_check = cell_edac_check;
+       cell_edac_init_csrows(mci);
+
+       /* Register with EDAC core */
+       rc = edac_mc_add_mc(mci);
+       if (rc) {
+               dev_err(&pdev->dev, "failed to register with EDAC core\n");
+               edac_mc_free(mci);
+               return rc;
+       }
+
+       return 0;
+}
+
+static int __devexit cell_edac_remove(struct platform_device *pdev)
+{
+       struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev);
+       if (mci)
+               edac_mc_free(mci);
+       return 0;
+}
+
+static struct platform_driver cell_edac_driver = {
+       .driver         = {
+               .name   = "cbe-mic",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = cell_edac_probe,
+       .remove         = cell_edac_remove,
+};
+
+static int __init cell_edac_init(void)
+{
+       /* Sanity check registers data structure */
+       BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
+                             mic_df_ecc_address_0) != 0xf8);
+       BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
+                             mic_df_ecc_address_1) != 0x1b8);
+       BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
+                             mic_df_config) != 0x218);
+       BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
+                             mic_fir) != 0x230);
+       BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
+                             mic_mnt_cfg) != 0x210);
+       BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
+                             mic_exc) != 0x208);
+
+       return platform_driver_register(&cell_edac_driver);
+}
+
+static void __exit cell_edac_exit(void)
+{
+       platform_driver_unregister(&cell_edac_driver);
+}
+
+module_init(cell_edac_init);
+module_exit(cell_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("ECC counting for Cell MIC");
index 2d23e304f5ec1083b9850e46fe817c74b4e78d00..a9aa845dbe74c864d9b5126d272051b5e18223f6 100644 (file)
@@ -136,6 +136,7 @@ enum mem_type {
        MEM_DDR2,               /* DDR2 RAM */
        MEM_FB_DDR2,            /* fully buffered DDR2 */
        MEM_RDDR2,              /* Registered DDR2 RAM */
+       MEM_XDR,                /* Rambus XDR */
 };
 
 #define MEM_FLAG_EMPTY         BIT(MEM_EMPTY)
@@ -152,6 +153,7 @@ enum mem_type {
 #define MEM_FLAG_DDR2           BIT(MEM_DDR2)
 #define MEM_FLAG_FB_DDR2        BIT(MEM_FB_DDR2)
 #define MEM_FLAG_RDDR2          BIT(MEM_RDDR2)
+#define MEM_FLAG_XDR            BIT(MEM_XDR)
 
 /* chipset Error Detection and Correction capabilities and mode */
 enum edac_type {
index f3690a697cf98a88e51e57f02d36bac13bdd1580..b9552bc03dead83ee02788de4c57979f038d54ad 100644 (file)
@@ -155,6 +155,10 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
        dev_ctl->instances = dev_inst;
        dev_ctl->pvt_info = pvt;
 
+       /* Default logging of CEs and UEs */
+       dev_ctl->log_ce = 1;
+       dev_ctl->log_ue = 1;
+
        /* Name of this edac device */
        snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);
 
@@ -436,7 +440,7 @@ static void edac_device_workq_function(struct work_struct *work_req)
         */
        if (edac_dev->poll_msec == 1000)
                queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               round_jiffies(edac_dev->delay));
+                               round_jiffies_relative(edac_dev->delay));
        else
                queue_delayed_work(edac_workqueue, &edac_dev->work,
                                edac_dev->delay);
@@ -468,7 +472,7 @@ void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
         */
        if (edac_dev->poll_msec == 1000)
                queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               round_jiffies(edac_dev->delay));
+                               round_jiffies_relative(edac_dev->delay));
        else
                queue_delayed_work(edac_workqueue, &edac_dev->work,
                                edac_dev->delay);
index 9aac88027fb31f8a7398fa33173c396983fd7ad2..021d18795145cbc364e676d763ed8369ccea8ee1 100644 (file)
@@ -73,7 +73,8 @@ static const char *mem_types[] = {
        [MEM_RMBS] = "RMBS",
        [MEM_DDR2] = "Unbuffered-DDR2",
        [MEM_FB_DDR2] = "FullyBuffered-DDR2",
-       [MEM_RDDR2] = "Registered-DDR2"
+       [MEM_RDDR2] = "Registered-DDR2",
+       [MEM_XDR] = "XDR"
 };
 
 static const char *dev_types[] = {
index e0b47b74ec4581aa60dda973c612bddc6c5738ca..32be43576a8ee720876604a6b0c11c9081b2c0c7 100644 (file)
@@ -246,7 +246,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
                /* if we are on a one second period, then use round */
                msec = edac_pci_get_poll_msec();
                if (msec == 1000)
-                       delay = round_jiffies(msecs_to_jiffies(msec));
+                       delay = round_jiffies_relative(msecs_to_jiffies(msec));
                else
                        delay = msecs_to_jiffies(msec);
 
index 5b075da9914511ffebcb3f2de1362988957a9c3c..71c3195d3704428fc16a3f69848d739f0a8d723e 100644 (file)
@@ -558,8 +558,10 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
 
        debugf4("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
 
-       /* check the status reg for errors */
-       if (status) {
+       /* check the status reg for errors on boards NOT marked as broken
+        * if broken, we cannot trust any of the status bits
+        */
+       if (status && !dev->broken_parity_status) {
                if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
                        edac_printk(KERN_CRIT, EDAC_PCI,
                                "Signaled System Error on %s\n",
@@ -593,8 +595,10 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
 
                debugf4("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
 
-               /* check the secondary status reg for errors */
-               if (status) {
+               /* check the secondary status reg for errors,
+                * on NOT broken boards
+                */
+               if (status && !dev->broken_parity_status) {
                        if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
                                edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
                                        "Signaled System Error on %s\n",
index e895f9f887abb8dbda0c45706e649a8cff8fd9c8..5d4292811c146285f45acc0f47ebe0618d210127 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
+#include <linux/edac.h>
 #include "edac_core.h"
 
 #define I3000_REVISION         "1.1"
 #define I3000_MCHBAR_MASK      0xffffc000
 #define I3000_MMR_WINDOW_SIZE  16384
 
-#define I3000_EDEAP            0x70    /* Extended DRAM Error Address Pointer (8b)
-                                        *
-                                        * 7:1   reserved
-                                        * 0     bit 32 of address
-                                        */
-#define I3000_DEAP             0x58    /* DRAM Error Address Pointer (32b)
-                                        *
-                                        * 31:7  address
-                                        * 6:1   reserved
-                                        * 0     Error channel 0/1
-                                        */
-#define I3000_DEAP_GRAIN       (1 << 7)
-#define I3000_DEAP_PFN(edeap, deap)    ((((edeap) & 1) << (32 - PAGE_SHIFT)) | \
-                                       ((deap) >> PAGE_SHIFT))
-#define I3000_DEAP_OFFSET(deap)                ((deap) & ~(I3000_DEAP_GRAIN-1) & ~PAGE_MASK)
-#define I3000_DEAP_CHANNEL(deap)       ((deap) & 1)
-
-#define I3000_DERRSYN          0x5c    /* DRAM Error Syndrome (8b)
-                                        *
-                                        *  7:0  DRAM ECC Syndrome
-                                        */
-
-#define I3000_ERRSTS           0xc8    /* Error Status Register (16b)
-                                        *
-                                        * 15:12 reserved
-                                        * 11    MCH Thermal Sensor Event for SMI/SCI/SERR
-                                        * 10    reserved
-                                        *  9    LOCK to non-DRAM Memory Flag (LCKF)
-                                        *  8    Received Refresh Timeout Flag (RRTOF)
-                                        *  7:2  reserved
-                                        *  1    Multiple-bit DRAM ECC Error Flag (DMERR)
-                                        *  0    Single-bit DRAM ECC Error Flag (DSERR)
-                                        */
+#define I3000_EDEAP    0x70    /* Extended DRAM Error Address Pointer (8b)
+                                *
+                                * 7:1   reserved
+                                * 0     bit 32 of address
+                                */
+#define I3000_DEAP     0x58    /* DRAM Error Address Pointer (32b)
+                                *
+                                * 31:7  address
+                                * 6:1   reserved
+                                * 0     Error channel 0/1
+                                */
+#define I3000_DEAP_GRAIN               (1 << 7)
+
+/*
+ * Helper functions to decode the DEAP/EDEAP hardware registers.
+ *
+ * The type promotion here is deliberate; we're deriving an
+ * unsigned long pfn and offset from hardware regs which are u8/u32.
+ */
+
+static inline unsigned long deap_pfn(u8 edeap, u32 deap)
+{
+       deap >>= PAGE_SHIFT;
+       deap |= (edeap & 1) << (32 - PAGE_SHIFT);
+       return deap;
+}
+
+static inline unsigned long deap_offset(u32 deap)
+{
+       return deap & ~(I3000_DEAP_GRAIN - 1) & ~PAGE_MASK;
+}
+
+static inline int deap_channel(u32 deap)
+{
+       return deap & 1;
+}
+
+#define I3000_DERRSYN  0x5c    /* DRAM Error Syndrome (8b)
+                                *
+                                *  7:0  DRAM ECC Syndrome
+                                */
+
+#define I3000_ERRSTS   0xc8    /* Error Status Register (16b)
+                                *
+                                * 15:12 reserved
+                                * 11    MCH Thermal Sensor Event
+                                *         for SMI/SCI/SERR
+                                * 10    reserved
+                                *  9    LOCK to non-DRAM Memory Flag (LCKF)
+                                *  8    Received Refresh Timeout Flag (RRTOF)
+                                *  7:2  reserved
+                                *  1    Multi-bit DRAM ECC Error Flag (DMERR)
+                                *  0    Single-bit DRAM ECC Error Flag (DSERR)
+                                */
 #define I3000_ERRSTS_BITS      0x0b03  /* bits which indicate errors */
 #define I3000_ERRSTS_UE                0x0002
 #define I3000_ERRSTS_CE                0x0001
 
-#define I3000_ERRCMD           0xca    /* Error Command (16b)
-                                        *
-                                        * 15:12 reserved
-                                        * 11    SERR on MCH Thermal Sensor Event (TSESERR)
-                                        * 10    reserved
-                                        *  9    SERR on LOCK to non-DRAM Memory (LCKERR)
-                                        *  8    SERR on DRAM Refresh Timeout (DRTOERR)
-                                        *  7:2  reserved
-                                        *  1    SERR Multiple-Bit DRAM ECC Error (DMERR)
-                                        *  0    SERR on Single-Bit ECC Error (DSERR)
-                                        */
+#define I3000_ERRCMD   0xca    /* Error Command (16b)
+                                *
+                                * 15:12 reserved
+                                * 11    SERR on MCH Thermal Sensor Event
+                                *         (TSESERR)
+                                * 10    reserved
+                                *  9    SERR on LOCK to non-DRAM Memory
+                                *         (LCKERR)
+                                *  8    SERR on DRAM Refresh Timeout
+                                *         (DRTOERR)
+                                *  7:2  reserved
+                                *  1    SERR Multi-Bit DRAM ECC Error
+                                *         (DMERR)
+                                *  0    SERR on Single-Bit ECC Error
+                                *         (DSERR)
+                                */
 
 /* Intel  MMIO register space - device 0 function 0 - MMR space */
 
 #define I3000_DRB_SHIFT 25     /* 32MiB grain */
 
-#define I3000_C0DRB            0x100   /* Channel 0 DRAM Rank Boundary (8b x 4)
-                                        *
-                                        * 7:0   Channel 0 DRAM Rank Boundary Address
-                                        */
-#define I3000_C1DRB            0x180   /* Channel 1 DRAM Rank Boundary (8b x 4)
-                                        *
-                                        * 7:0   Channel 1 DRAM Rank Boundary Address
-                                        */
-
-#define I3000_C0DRA            0x108   /* Channel 0 DRAM Rank Attribute (8b x 2)
-                                        *
-                                        * 7     reserved
-                                        * 6:4   DRAM odd Rank Attribute
-                                        * 3     reserved
-                                        * 2:0   DRAM even Rank Attribute
-                                        *
-                                        * Each attribute defines the page
-                                        * size of the corresponding rank:
-                                        *     000: unpopulated
-                                        *     001: reserved
-                                        *     010: 4 KB
-                                        *     011: 8 KB
-                                        *     100: 16 KB
-                                        *     Others: reserved
-                                        */
-#define I3000_C1DRA            0x188   /* Channel 1 DRAM Rank Attribute (8b x 2) */
-#define ODD_RANK_ATTRIB(dra) (((dra) & 0x70) >> 4)
-#define EVEN_RANK_ATTRIB(dra) ((dra) & 0x07)
-
-#define I3000_C0DRC0           0x120   /* DRAM Controller Mode 0 (32b)
-                                        *
-                                        * 31:30 reserved
-                                        * 29    Initialization Complete (IC)
-                                        * 28:11 reserved
-                                        * 10:8  Refresh Mode Select (RMS)
-                                        * 7     reserved
-                                        * 6:4   Mode Select (SMS)
-                                        * 3:2   reserved
-                                        * 1:0   DRAM Type (DT)
-                                        */
-
-#define I3000_C0DRC1           0x124   /* DRAM Controller Mode 1 (32b)
-                                        *
-                                        * 31    Enhanced Addressing Enable (ENHADE)
-                                        * 30:0  reserved
-                                        */
+#define I3000_C0DRB    0x100   /* Channel 0 DRAM Rank Boundary (8b x 4)
+                                *
+                                * 7:0   Channel 0 DRAM Rank Boundary Address
+                                */
+#define I3000_C1DRB    0x180   /* Channel 1 DRAM Rank Boundary (8b x 4)
+                                *
+                                * 7:0   Channel 1 DRAM Rank Boundary Address
+                                */
+
+#define I3000_C0DRA    0x108   /* Channel 0 DRAM Rank Attribute (8b x 2)
+                                *
+                                * 7     reserved
+                                * 6:4   DRAM odd Rank Attribute
+                                * 3     reserved
+                                * 2:0   DRAM even Rank Attribute
+                                *
+                                * Each attribute defines the page
+                                * size of the corresponding rank:
+                                *     000: unpopulated
+                                *     001: reserved
+                                *     010: 4 KB
+                                *     011: 8 KB
+                                *     100: 16 KB
+                                *     Others: reserved
+                                */
+#define I3000_C1DRA    0x188   /* Channel 1 DRAM Rank Attribute (8b x 2) */
+
+static inline unsigned char odd_rank_attrib(unsigned char dra)
+{
+       return (dra & 0x70) >> 4;
+}
+
+static inline unsigned char even_rank_attrib(unsigned char dra)
+{
+       return dra & 0x07;
+}
+
+#define I3000_C0DRC0   0x120   /* DRAM Controller Mode 0 (32b)
+                                *
+                                * 31:30 reserved
+                                * 29    Initialization Complete (IC)
+                                * 28:11 reserved
+                                * 10:8  Refresh Mode Select (RMS)
+                                * 7     reserved
+                                * 6:4   Mode Select (SMS)
+                                * 3:2   reserved
+                                * 1:0   DRAM Type (DT)
+                                */
+
+#define I3000_C0DRC1   0x124   /* DRAM Controller Mode 1 (32b)
+                                *
+                                * 31    Enhanced Addressing Enable (ENHADE)
+                                * 30:0  reserved
+                                */
 
 enum i3000p_chips {
        I3000 = 0,
@@ -187,7 +222,8 @@ static void i3000_get_error_info(struct mem_ctl_info *mci,
                pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn);
        }
 
-       /* Clear any error bits.
+       /*
+        * Clear any error bits.
         * (Yes, we really clear bits by writing 1 to them.)
         */
        pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
@@ -198,8 +234,8 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
                                struct i3000_error_info *info,
                                int handle_errors)
 {
-       int row, multi_chan;
-       int pfn, offset, channel;
+       int row, multi_chan, channel;
+       unsigned long pfn, offset;
 
        multi_chan = mci->csrows[0].nr_channels - 1;
 
@@ -214,9 +250,9 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
                info->errsts = info->errsts2;
        }
 
-       pfn = I3000_DEAP_PFN(info->edeap, info->deap);
-       offset = I3000_DEAP_OFFSET(info->deap);
-       channel = I3000_DEAP_CHANNEL(info->deap);
+       pfn = deap_pfn(info->edeap, info->deap);
+       offset = deap_offset(info->deap);
+       channel = deap_channel(info->deap);
 
        row = edac_mc_find_csrow_by_page(mci, pfn);
 
@@ -245,16 +281,18 @@ static int i3000_is_interleaved(const unsigned char *c0dra,
 {
        int i;
 
-       /* If the channels aren't populated identically then
+       /*
+        * If the channels aren't populated identically then
         * we're not interleaved.
         */
        for (i = 0; i < I3000_RANKS_PER_CHANNEL / 2; i++)
-               if (ODD_RANK_ATTRIB(c0dra[i]) != ODD_RANK_ATTRIB(c1dra[i]) ||
-                       EVEN_RANK_ATTRIB(c0dra[i]) !=
-                                               EVEN_RANK_ATTRIB(c1dra[i]))
+               if (odd_rank_attrib(c0dra[i]) != odd_rank_attrib(c1dra[i]) ||
+                       even_rank_attrib(c0dra[i]) !=
+                                               even_rank_attrib(c1dra[i]))
                        return 0;
 
-       /* If the rank boundaries for the two channels are different
+       /*
+        * If the rank boundaries for the two channels are different
         * then we're not interleaved.
         */
        for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++)
@@ -288,6 +326,15 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
                return -ENODEV;
        }
 
+       switch (edac_op_state) {
+       case EDAC_OPSTATE_POLL:
+       case EDAC_OPSTATE_NMI:
+               break;
+       default:
+               edac_op_state = EDAC_OPSTATE_POLL;
+               break;
+       }
+
        c0dra[0] = readb(window + I3000_C0DRA + 0);     /* ranks 0,1 */
        c0dra[1] = readb(window + I3000_C0DRA + 1);     /* ranks 2,3 */
        c1dra[0] = readb(window + I3000_C1DRA + 0);     /* ranks 0,1 */
@@ -300,7 +347,8 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 
        iounmap(window);
 
-       /* Figure out how many channels we have.
+       /*
+        * Figure out how many channels we have.
         *
         * If we have what the datasheet calls "asymmetric channels"
         * (essentially the same as what was called "virtual single
@@ -363,7 +411,8 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
                csrow->edac_mode = EDAC_UNKNOWN;
        }
 
-       /* Clear any error bits.
+       /*
+        * Clear any error bits.
         * (Yes, we really clear bits by writing 1 to them.)
         */
        pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
@@ -390,7 +439,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
        debugf3("MC: %s(): success\n", __func__);
        return 0;
 
-      fail:
+fail:
        if (mci)
                edac_mc_free(mci);
 
@@ -409,7 +458,7 @@ static int __devinit i3000_init_one(struct pci_dev *pdev,
                return -EIO;
 
        rc = i3000_probe1(pdev, ent->driver_data);
-       if (mci_pdev == NULL)
+       if (!mci_pdev)
                mci_pdev = pci_dev_get(pdev);
 
        return rc;
@@ -424,7 +473,8 @@ static void __devexit i3000_remove_one(struct pci_dev *pdev)
        if (i3000_pci)
                edac_pci_release_generic_ctl(i3000_pci);
 
-       if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+       mci = edac_mc_del_mc(&pdev->dev);
+       if (!mci)
                return;
 
        edac_mc_free(mci);
@@ -457,7 +507,7 @@ static int __init i3000_init(void)
        if (pci_rc < 0)
                goto fail0;
 
-       if (mci_pdev == NULL) {
+       if (!mci_pdev) {
                i3000_registered = 0;
                mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                        PCI_DEVICE_ID_INTEL_3000_HB, NULL);
@@ -504,3 +554,6 @@ module_exit(i3000_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Akamai Technologies Arthur Ulfeldt/Jason Uhlenkott");
 MODULE_DESCRIPTION("MC support for Intel 3000 memory hub controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
new file mode 100644 (file)
index 0000000..065732d
--- /dev/null
@@ -0,0 +1,1043 @@
+/*
+ * Freescale MPC85xx Memory Controller kenel module
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/edac.h>
+
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <asm/mpc85xx.h>
+#include "edac_module.h"
+#include "edac_core.h"
+#include "mpc85xx_edac.h"
+
+static int edac_dev_idx;
+static int edac_pci_idx;
+static int edac_mc_idx;
+
+static u32 orig_ddr_err_disable;
+static u32 orig_ddr_err_sbe;
+
+/*
+ * PCI Err defines
+ */
+#ifdef CONFIG_PCI
+static u32 orig_pci_err_cap_dr;
+static u32 orig_pci_err_en;
+#endif
+
+static u32 orig_l2_err_disable;
+static u32 orig_hid1;
+
+static const char *mpc85xx_ctl_name = "MPC85xx";
+
+/************************ MC SYSFS parts ***********************************/
+
+static ssize_t mpc85xx_mc_inject_data_hi_show(struct mem_ctl_info *mci,
+                                             char *data)
+{
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+       return sprintf(data, "0x%08x",
+                      in_be32(pdata->mc_vbase +
+                              MPC85XX_MC_DATA_ERR_INJECT_HI));
+}
+
+static ssize_t mpc85xx_mc_inject_data_lo_show(struct mem_ctl_info *mci,
+                                             char *data)
+{
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+       return sprintf(data, "0x%08x",
+                      in_be32(pdata->mc_vbase +
+                              MPC85XX_MC_DATA_ERR_INJECT_LO));
+}
+
+static ssize_t mpc85xx_mc_inject_ctrl_show(struct mem_ctl_info *mci, char *data)
+{
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+       return sprintf(data, "0x%08x",
+                      in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT));
+}
+
+static ssize_t mpc85xx_mc_inject_data_hi_store(struct mem_ctl_info *mci,
+                                              const char *data, size_t count)
+{
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+       if (isdigit(*data)) {
+               out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI,
+                        simple_strtoul(data, NULL, 0));
+               return count;
+       }
+       return 0;
+}
+
+static ssize_t mpc85xx_mc_inject_data_lo_store(struct mem_ctl_info *mci,
+                                              const char *data, size_t count)
+{
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+       if (isdigit(*data)) {
+               out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO,
+                        simple_strtoul(data, NULL, 0));
+               return count;
+       }
+       return 0;
+}
+
+static ssize_t mpc85xx_mc_inject_ctrl_store(struct mem_ctl_info *mci,
+                                           const char *data, size_t count)
+{
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+       if (isdigit(*data)) {
+               out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT,
+                        simple_strtoul(data, NULL, 0));
+               return count;
+       }
+       return 0;
+}
+
+static struct mcidev_sysfs_attribute mpc85xx_mc_sysfs_attributes[] = {
+       {
+        .attr = {
+                 .name = "inject_data_hi",
+                 .mode = (S_IRUGO | S_IWUSR)
+                 },
+        .show = mpc85xx_mc_inject_data_hi_show,
+        .store = mpc85xx_mc_inject_data_hi_store},
+       {
+        .attr = {
+                 .name = "inject_data_lo",
+                 .mode = (S_IRUGO | S_IWUSR)
+                 },
+        .show = mpc85xx_mc_inject_data_lo_show,
+        .store = mpc85xx_mc_inject_data_lo_store},
+       {
+        .attr = {
+                 .name = "inject_ctrl",
+                 .mode = (S_IRUGO | S_IWUSR)
+                 },
+        .show = mpc85xx_mc_inject_ctrl_show,
+        .store = mpc85xx_mc_inject_ctrl_store},
+
+       /* End of list */
+       {
+        .attr = {.name = NULL}
+        }
+};
+
+static void mpc85xx_set_mc_sysfs_attributes(struct mem_ctl_info *mci)
+{
+       mci->mc_driver_sysfs_attributes = mpc85xx_mc_sysfs_attributes;
+}
+
+/**************************** PCI Err device ***************************/
+#ifdef CONFIG_PCI
+
+static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)
+{
+       struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
+       u32 err_detect;
+
+       err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
+
+       /* master aborts can happen during PCI config cycles */
+       if (!(err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_MST_ABRT))) {
+               out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
+               return;
+       }
+
+       printk(KERN_ERR "PCI error(s) detected\n");
+       printk(KERN_ERR "PCI/X ERR_DR register: %#08x\n", err_detect);
+
+       printk(KERN_ERR "PCI/X ERR_ATTRIB register: %#08x\n",
+              in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ATTRIB));
+       printk(KERN_ERR "PCI/X ERR_ADDR register: %#08x\n",
+              in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR));
+       printk(KERN_ERR "PCI/X ERR_EXT_ADDR register: %#08x\n",
+              in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EXT_ADDR));
+       printk(KERN_ERR "PCI/X ERR_DL register: %#08x\n",
+              in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DL));
+       printk(KERN_ERR "PCI/X ERR_DH register: %#08x\n",
+              in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DH));
+
+       /* clear error bits */
+       out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
+
+       if (err_detect & PCI_EDE_PERR_MASK)
+               edac_pci_handle_pe(pci, pci->ctl_name);
+
+       if ((err_detect & ~PCI_EDE_MULTI_ERR) & ~PCI_EDE_PERR_MASK)
+               edac_pci_handle_npe(pci, pci->ctl_name);
+}
+
+static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
+{
+       struct edac_pci_ctl_info *pci = dev_id;
+       struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
+       u32 err_detect;
+
+       err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
+
+       if (!err_detect)
+               return IRQ_NONE;
+
+       mpc85xx_pci_check(pci);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit mpc85xx_pci_err_probe(struct platform_device *pdev)
+{
+       struct edac_pci_ctl_info *pci;
+       struct mpc85xx_pci_pdata *pdata;
+       struct resource *r;
+       int res = 0;
+
+       if (!devres_open_group(&pdev->dev, mpc85xx_pci_err_probe, GFP_KERNEL))
+               return -ENOMEM;
+
+       pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mpc85xx_pci_err");
+       if (!pci)
+               return -ENOMEM;
+
+       pdata = pci->pvt_info;
+       pdata->name = "mpc85xx_pci_err";
+       pdata->irq = NO_IRQ;
+       platform_set_drvdata(pdev, pci);
+       pci->dev = &pdev->dev;
+       pci->mod_name = EDAC_MOD_STR;
+       pci->ctl_name = pdata->name;
+       pci->dev_name = pdev->dev.bus_id;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               pci->edac_check = mpc85xx_pci_check;
+
+       pdata->edac_idx = edac_pci_idx++;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               printk(KERN_ERR "%s: Unable to get resource for "
+                      "PCI err regs\n", __func__);
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev, r->start,
+                                    r->end - r->start + 1, pdata->name)) {
+               printk(KERN_ERR "%s: Error while requesting mem region\n",
+                      __func__);
+               res = -EBUSY;
+               goto err;
+       }
+
+       pdata->pci_vbase = devm_ioremap(&pdev->dev, r->start,
+                                       r->end - r->start + 1);
+       if (!pdata->pci_vbase) {
+               printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
+               res = -ENOMEM;
+               goto err;
+       }
+
+       orig_pci_err_cap_dr =
+           in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
+
+       /* PCI master abort is expected during config cycles */
+       out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);
+
+       orig_pci_err_en = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
+
+       /* disable master abort reporting */
+       out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
+
+       /* clear error bits */
+       out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
+
+       if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
+               debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+               goto err;
+       }
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               pdata->irq = platform_get_irq(pdev, 0);
+               res = devm_request_irq(&pdev->dev, pdata->irq,
+                                      mpc85xx_pci_isr, IRQF_DISABLED,
+                                      "[EDAC] PCI err", pci);
+               if (res < 0) {
+                       printk(KERN_ERR
+                              "%s: Unable to requiest irq %d for "
+                              "MPC85xx PCI err\n", __func__, pdata->irq);
+                       res = -ENODEV;
+                       goto err2;
+               }
+
+               printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n",
+                      pdata->irq);
+       }
+
+       devres_remove_group(&pdev->dev, mpc85xx_pci_err_probe);
+       debugf3("%s(): success\n", __func__);
+       printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
+
+       return 0;
+
+err2:
+       edac_pci_del_device(&pdev->dev);
+err:
+       edac_pci_free_ctl_info(pci);
+       devres_release_group(&pdev->dev, mpc85xx_pci_err_probe);
+       return res;
+}
+
+static int mpc85xx_pci_err_remove(struct platform_device *pdev)
+{
+       struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
+       struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
+
+       debugf0("%s()\n", __func__);
+
+       out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR,
+                orig_pci_err_cap_dr);
+
+       out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, orig_pci_err_en);
+
+       edac_pci_del_device(pci->dev);
+
+       if (edac_op_state == EDAC_OPSTATE_INT)
+               irq_dispose_mapping(pdata->irq);
+
+       edac_pci_free_ctl_info(pci);
+
+       return 0;
+}
+
+static struct platform_driver mpc85xx_pci_err_driver = {
+       .probe = mpc85xx_pci_err_probe,
+       .remove = __devexit_p(mpc85xx_pci_err_remove),
+       .driver = {
+               .name = "mpc85xx_pci_err",
+       }
+};
+
+#endif                         /* CONFIG_PCI */
+
+/**************************** L2 Err device ***************************/
+
+/************************ L2 SYSFS parts ***********************************/
+
+static ssize_t mpc85xx_l2_inject_data_hi_show(struct edac_device_ctl_info
+                                             *edac_dev, char *data)
+{
+       struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
+       return sprintf(data, "0x%08x",
+                      in_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJHI));
+}
+
+static ssize_t mpc85xx_l2_inject_data_lo_show(struct edac_device_ctl_info
+                                             *edac_dev, char *data)
+{
+       struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
+       return sprintf(data, "0x%08x",
+                      in_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJLO));
+}
+
+static ssize_t mpc85xx_l2_inject_ctrl_show(struct edac_device_ctl_info
+                                          *edac_dev, char *data)
+{
+       struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
+       return sprintf(data, "0x%08x",
+                      in_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJCTL));
+}
+
+static ssize_t mpc85xx_l2_inject_data_hi_store(struct edac_device_ctl_info
+                                              *edac_dev, const char *data,
+                                              size_t count)
+{
+       struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
+       if (isdigit(*data)) {
+               out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJHI,
+                        simple_strtoul(data, NULL, 0));
+               return count;
+       }
+       return 0;
+}
+
+static ssize_t mpc85xx_l2_inject_data_lo_store(struct edac_device_ctl_info
+                                              *edac_dev, const char *data,
+                                              size_t count)
+{
+       struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
+       if (isdigit(*data)) {
+               out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJLO,
+                        simple_strtoul(data, NULL, 0));
+               return count;
+       }
+       return 0;
+}
+
+static ssize_t mpc85xx_l2_inject_ctrl_store(struct edac_device_ctl_info
+                                           *edac_dev, const char *data,
+                                           size_t count)
+{
+       struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
+       if (isdigit(*data)) {
+               out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJCTL,
+                        simple_strtoul(data, NULL, 0));
+               return count;
+       }
+       return 0;
+}
+
+static struct edac_dev_sysfs_attribute mpc85xx_l2_sysfs_attributes[] = {
+       {
+        .attr = {
+                 .name = "inject_data_hi",
+                 .mode = (S_IRUGO | S_IWUSR)
+                 },
+        .show = mpc85xx_l2_inject_data_hi_show,
+        .store = mpc85xx_l2_inject_data_hi_store},
+       {
+        .attr = {
+                 .name = "inject_data_lo",
+                 .mode = (S_IRUGO | S_IWUSR)
+                 },
+        .show = mpc85xx_l2_inject_data_lo_show,
+        .store = mpc85xx_l2_inject_data_lo_store},
+       {
+        .attr = {
+                 .name = "inject_ctrl",
+                 .mode = (S_IRUGO | S_IWUSR)
+                 },
+        .show = mpc85xx_l2_inject_ctrl_show,
+        .store = mpc85xx_l2_inject_ctrl_store},
+
+       /* End of list */
+       {
+        .attr = {.name = NULL}
+        }
+};
+
+static void mpc85xx_set_l2_sysfs_attributes(struct edac_device_ctl_info
+                                           *edac_dev)
+{
+       edac_dev->sysfs_attributes = mpc85xx_l2_sysfs_attributes;
+}
+
+/***************************** L2 ops ***********************************/
+
+static void mpc85xx_l2_check(struct edac_device_ctl_info *edac_dev)
+{
+       struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
+       u32 err_detect;
+
+       err_detect = in_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET);
+
+       if (!(err_detect & L2_EDE_MASK))
+               return;
+
+       printk(KERN_ERR "ECC Error in CPU L2 cache\n");
+       printk(KERN_ERR "L2 Error Detect Register: 0x%08x\n", err_detect);
+       printk(KERN_ERR "L2 Error Capture Data High Register: 0x%08x\n",
+              in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATAHI));
+       printk(KERN_ERR "L2 Error Capture Data Lo Register: 0x%08x\n",
+              in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATALO));
+       printk(KERN_ERR "L2 Error Syndrome Register: 0x%08x\n",
+              in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTECC));
+       printk(KERN_ERR "L2 Error Attributes Capture Register: 0x%08x\n",
+              in_be32(pdata->l2_vbase + MPC85XX_L2_ERRATTR));
+       printk(KERN_ERR "L2 Error Address Capture Register: 0x%08x\n",
+              in_be32(pdata->l2_vbase + MPC85XX_L2_ERRADDR));
+
+       /* clear error detect register */
+       out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET, err_detect);
+
+       if (err_detect & L2_EDE_CE_MASK)
+               edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
+
+       if (err_detect & L2_EDE_UE_MASK)
+               edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
+}
+
+static irqreturn_t mpc85xx_l2_isr(int irq, void *dev_id)
+{
+       struct edac_device_ctl_info *edac_dev = dev_id;
+       struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
+       u32 err_detect;
+
+       err_detect = in_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET);
+
+       if (!(err_detect & L2_EDE_MASK))
+               return IRQ_NONE;
+
+       mpc85xx_l2_check(edac_dev);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit mpc85xx_l2_err_probe(struct of_device *op,
+                                         const struct of_device_id *match)
+{
+       struct edac_device_ctl_info *edac_dev;
+       struct mpc85xx_l2_pdata *pdata;
+       struct resource r;
+       int res;
+
+       if (!devres_open_group(&op->dev, mpc85xx_l2_err_probe, GFP_KERNEL))
+               return -ENOMEM;
+
+       edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
+                                             "cpu", 1, "L", 1, 2, NULL, 0,
+                                             edac_dev_idx);
+       if (!edac_dev) {
+               devres_release_group(&op->dev, mpc85xx_l2_err_probe);
+               return -ENOMEM;
+       }
+
+       pdata = edac_dev->pvt_info;
+       pdata->name = "mpc85xx_l2_err";
+       pdata->irq = NO_IRQ;
+       edac_dev->dev = &op->dev;
+       dev_set_drvdata(edac_dev->dev, edac_dev);
+       edac_dev->ctl_name = pdata->name;
+       edac_dev->dev_name = pdata->name;
+
+       res = of_address_to_resource(op->node, 0, &r);
+       if (res) {
+               printk(KERN_ERR "%s: Unable to get resource for "
+                      "L2 err regs\n", __func__);
+               goto err;
+       }
+
+       /* we only need the error registers */
+       r.start += 0xe00;
+
+       if (!devm_request_mem_region(&op->dev, r.start,
+                                    r.end - r.start + 1, pdata->name)) {
+               printk(KERN_ERR "%s: Error while requesting mem region\n",
+                      __func__);
+               res = -EBUSY;
+               goto err;
+       }
+
+       pdata->l2_vbase = devm_ioremap(&op->dev, r.start, r.end - r.start + 1);
+       if (!pdata->l2_vbase) {
+               printk(KERN_ERR "%s: Unable to setup L2 err regs\n", __func__);
+               res = -ENOMEM;
+               goto err;
+       }
+
+       out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET, ~0);
+
+       orig_l2_err_disable = in_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS);
+
+       /* clear the err_dis */
+       out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS, 0);
+
+       edac_dev->mod_name = EDAC_MOD_STR;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               edac_dev->edac_check = mpc85xx_l2_check;
+
+       mpc85xx_set_l2_sysfs_attributes(edac_dev);
+
+       pdata->edac_idx = edac_dev_idx++;
+
+       if (edac_device_add_device(edac_dev) > 0) {
+               debugf3("%s(): failed edac_device_add_device()\n", __func__);
+               goto err;
+       }
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               pdata->irq = irq_of_parse_and_map(op->node, 0);
+               res = devm_request_irq(&op->dev, pdata->irq,
+                                      mpc85xx_l2_isr, IRQF_DISABLED,
+                                      "[EDAC] L2 err", edac_dev);
+               if (res < 0) {
+                       printk(KERN_ERR
+                              "%s: Unable to requiest irq %d for "
+                              "MPC85xx L2 err\n", __func__, pdata->irq);
+                       irq_dispose_mapping(pdata->irq);
+                       res = -ENODEV;
+                       goto err2;
+               }
+
+               printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for L2 Err\n",
+                      pdata->irq);
+
+               edac_dev->op_state = OP_RUNNING_INTERRUPT;
+
+               out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINTEN, L2_EIE_MASK);
+       }
+
+       devres_remove_group(&op->dev, mpc85xx_l2_err_probe);
+
+       debugf3("%s(): success\n", __func__);
+       printk(KERN_INFO EDAC_MOD_STR " L2 err registered\n");
+
+       return 0;
+
+err2:
+       edac_device_del_device(&op->dev);
+err:
+       devres_release_group(&op->dev, mpc85xx_l2_err_probe);
+       edac_device_free_ctl_info(edac_dev);
+       return res;
+}
+
+static int mpc85xx_l2_err_remove(struct of_device *op)
+{
+       struct edac_device_ctl_info *edac_dev = dev_get_drvdata(&op->dev);
+       struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
+
+       debugf0("%s()\n", __func__);
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINTEN, 0);
+               irq_dispose_mapping(pdata->irq);
+       }
+
+       out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS, orig_l2_err_disable);
+       edac_device_del_device(&op->dev);
+       edac_device_free_ctl_info(edac_dev);
+       return 0;
+}
+
+static struct of_device_id mpc85xx_l2_err_of_match[] = {
+       {
+        .compatible = "fsl,8540-l2-cache-controller",
+        },
+       {
+        .compatible = "fsl,8541-l2-cache-controller",
+        },
+       {
+        .compatible = "fsl,8544-l2-cache-controller",
+        },
+       {
+        .compatible = "fsl,8548-l2-cache-controller",
+        },
+       {
+        .compatible = "fsl,8555-l2-cache-controller",
+        },
+       {
+        .compatible = "fsl,8568-l2-cache-controller",
+        },
+       {},
+};
+
+static struct of_platform_driver mpc85xx_l2_err_driver = {
+       .owner = THIS_MODULE,
+       .name = "mpc85xx_l2_err",
+       .match_table = mpc85xx_l2_err_of_match,
+       .probe = mpc85xx_l2_err_probe,
+       .remove = mpc85xx_l2_err_remove,
+       .driver = {
+                  .name = "mpc85xx_l2_err",
+                  .owner = THIS_MODULE,
+                  },
+};
+
+/**************************** MC Err device ***************************/
+
+static void mpc85xx_mc_check(struct mem_ctl_info *mci)
+{
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+       struct csrow_info *csrow;
+       u32 err_detect;
+       u32 syndrome;
+       u32 err_addr;
+       u32 pfn;
+       int row_index;
+
+       err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT);
+       if (err_detect)
+               return;
+
+       mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n",
+                         err_detect);
+
+       /* no more processing if not ECC bit errors */
+       if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) {
+               out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect);
+               return;
+       }
+
+       syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC);
+       err_addr = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS);
+       pfn = err_addr >> PAGE_SHIFT;
+
+       for (row_index = 0; row_index < mci->nr_csrows; row_index++) {
+               csrow = &mci->csrows[row_index];
+               if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page))
+                       break;
+       }
+
+       mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data High: %#8.8x\n",
+                         in_be32(pdata->mc_vbase +
+                                 MPC85XX_MC_CAPTURE_DATA_HI));
+       mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data Low: %#8.8x\n",
+                         in_be32(pdata->mc_vbase +
+                                 MPC85XX_MC_CAPTURE_DATA_LO));
+       mpc85xx_mc_printk(mci, KERN_ERR, "syndrome: %#8.8x\n", syndrome);
+       mpc85xx_mc_printk(mci, KERN_ERR, "err addr: %#8.8x\n", err_addr);
+       mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn);
+
+       /* we are out of range */
+       if (row_index == mci->nr_csrows)
+               mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n");
+
+       if (err_detect & DDR_EDE_SBE)
+               edac_mc_handle_ce(mci, pfn, err_addr & PAGE_MASK,
+                                 syndrome, row_index, 0, mci->ctl_name);
+
+       if (err_detect & DDR_EDE_MBE)
+               edac_mc_handle_ue(mci, pfn, err_addr & PAGE_MASK,
+                                 row_index, mci->ctl_name);
+
+       out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect);
+}
+
+static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id)
+{
+       struct mem_ctl_info *mci = dev_id;
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+       u32 err_detect;
+
+       err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT);
+       if (!err_detect)
+               return IRQ_NONE;
+
+       mpc85xx_mc_check(mci);
+
+       return IRQ_HANDLED;
+}
+
+static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
+{
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+       struct csrow_info *csrow;
+       u32 sdram_ctl;
+       u32 sdtype;
+       enum mem_type mtype;
+       u32 cs_bnds;
+       int index;
+
+       sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG);
+
+       sdtype = sdram_ctl & DSC_SDTYPE_MASK;
+       if (sdram_ctl & DSC_RD_EN) {
+               switch (sdtype) {
+               case DSC_SDTYPE_DDR:
+                       mtype = MEM_RDDR;
+                       break;
+               case DSC_SDTYPE_DDR2:
+                       mtype = MEM_RDDR2;
+                       break;
+               default:
+                       mtype = MEM_UNKNOWN;
+                       break;
+               }
+       } else {
+               switch (sdtype) {
+               case DSC_SDTYPE_DDR:
+                       mtype = MEM_DDR;
+                       break;
+               case DSC_SDTYPE_DDR2:
+                       mtype = MEM_DDR2;
+                       break;
+               default:
+                       mtype = MEM_UNKNOWN;
+                       break;
+               }
+       }
+
+       for (index = 0; index < mci->nr_csrows; index++) {
+               u32 start;
+               u32 end;
+
+               csrow = &mci->csrows[index];
+               cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 +
+                                 (index * MPC85XX_MC_CS_BNDS_OFS));
+               start = (cs_bnds & 0xfff0000) << 4;
+               end = ((cs_bnds & 0xfff) << 20);
+               if (start)
+                       start |= 0xfffff;
+               if (end)
+                       end |= 0xfffff;
+
+               if (start == end)
+                       continue;       /* not populated */
+
+               csrow->first_page = start >> PAGE_SHIFT;
+               csrow->last_page = end >> PAGE_SHIFT;
+               csrow->nr_pages = csrow->last_page + 1 - csrow->first_page;
+               csrow->grain = 8;
+               csrow->mtype = mtype;
+               csrow->dtype = DEV_UNKNOWN;
+               if (sdram_ctl & DSC_X32_EN)
+                       csrow->dtype = DEV_X32;
+               csrow->edac_mode = EDAC_SECDED;
+       }
+}
+
+static int __devinit mpc85xx_mc_err_probe(struct of_device *op,
+                                         const struct of_device_id *match)
+{
+       struct mem_ctl_info *mci;
+       struct mpc85xx_mc_pdata *pdata;
+       struct resource r;
+       u32 sdram_ctl;
+       int res;
+
+       if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL))
+               return -ENOMEM;
+
+       mci = edac_mc_alloc(sizeof(*pdata), 4, 1, edac_mc_idx);
+       if (!mci) {
+               devres_release_group(&op->dev, mpc85xx_mc_err_probe);
+               return -ENOMEM;
+       }
+
+       pdata = mci->pvt_info;
+       pdata->name = "mpc85xx_mc_err";
+       pdata->irq = NO_IRQ;
+       mci->dev = &op->dev;
+       pdata->edac_idx = edac_mc_idx++;
+       dev_set_drvdata(mci->dev, mci);
+       mci->ctl_name = pdata->name;
+       mci->dev_name = pdata->name;
+
+       res = of_address_to_resource(op->node, 0, &r);
+       if (res) {
+               printk(KERN_ERR "%s: Unable to get resource for MC err regs\n",
+                      __func__);
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&op->dev, r.start,
+                                    r.end - r.start + 1, pdata->name)) {
+               printk(KERN_ERR "%s: Error while requesting mem region\n",
+                      __func__);
+               res = -EBUSY;
+               goto err;
+       }
+
+       pdata->mc_vbase = devm_ioremap(&op->dev, r.start, r.end - r.start + 1);
+       if (!pdata->mc_vbase) {
+               printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__);
+               res = -ENOMEM;
+               goto err;
+       }
+
+       sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG);
+       if (!(sdram_ctl & DSC_ECC_EN)) {
+               /* no ECC */
+               printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__);
+               res = -ENODEV;
+               goto err;
+       }
+
+       debugf3("%s(): init mci\n", __func__);
+       mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 |
+           MEM_FLAG_DDR | MEM_FLAG_DDR2;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+       mci->edac_cap = EDAC_FLAG_SECDED;
+       mci->mod_name = EDAC_MOD_STR;
+       mci->mod_ver = MPC85XX_REVISION;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               mci->edac_check = mpc85xx_mc_check;
+
+       mci->ctl_page_to_phys = NULL;
+
+       mci->scrub_mode = SCRUB_SW_SRC;
+
+       mpc85xx_set_mc_sysfs_attributes(mci);
+
+       mpc85xx_init_csrows(mci);
+
+#ifdef CONFIG_EDAC_DEBUG
+       edac_mc_register_mcidev_debug((struct attribute **)debug_attr);
+#endif
+
+       /* store the original error disable bits */
+       orig_ddr_err_disable =
+           in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE);
+       out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, 0);
+
+       /* clear all error bits */
+       out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0);
+
+       if (edac_mc_add_mc(mci)) {
+               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               goto err;
+       }
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN,
+                        DDR_EIE_MBEE | DDR_EIE_SBEE);
+
+               /* store the original error management threshold */
+               orig_ddr_err_sbe = in_be32(pdata->mc_vbase +
+                                          MPC85XX_MC_ERR_SBE) & 0xff0000;
+
+               /* set threshold to 1 error per interrupt */
+               out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000);
+
+               /* register interrupts */
+               pdata->irq = irq_of_parse_and_map(op->node, 0);
+               res = devm_request_irq(&op->dev, pdata->irq,
+                                      mpc85xx_mc_isr, IRQF_DISABLED,
+                                      "[EDAC] MC err", mci);
+               if (res < 0) {
+                       printk(KERN_ERR "%s: Unable to request irq %d for "
+                              "MPC85xx DRAM ERR\n", __func__, pdata->irq);
+                       irq_dispose_mapping(pdata->irq);
+                       res = -ENODEV;
+                       goto err2;
+               }
+
+               printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for MC\n",
+                      pdata->irq);
+       }
+
+       devres_remove_group(&op->dev, mpc85xx_mc_err_probe);
+       debugf3("%s(): success\n", __func__);
+       printk(KERN_INFO EDAC_MOD_STR " MC err registered\n");
+
+       return 0;
+
+err2:
+       edac_mc_del_mc(&op->dev);
+err:
+       devres_release_group(&op->dev, mpc85xx_mc_err_probe);
+       edac_mc_free(mci);
+       return res;
+}
+
+static int mpc85xx_mc_err_remove(struct of_device *op)
+{
+       struct mem_ctl_info *mci = dev_get_drvdata(&op->dev);
+       struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
+
+       debugf0("%s()\n", __func__);
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0);
+               irq_dispose_mapping(pdata->irq);
+       }
+
+       out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE,
+                orig_ddr_err_disable);
+       out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe);
+
+       edac_mc_del_mc(&op->dev);
+       edac_mc_free(mci);
+       return 0;
+}
+
+static struct of_device_id mpc85xx_mc_err_of_match[] = {
+       {
+        .compatible = "fsl,8540-memory-controller",
+        },
+       {
+        .compatible = "fsl,8541-memory-controller",
+        },
+       {
+        .compatible = "fsl,8544-memory-controller",
+        },
+       {
+        .compatible = "fsl,8548-memory-controller",
+        },
+       {
+        .compatible = "fsl,8555-memory-controller",
+        },
+       {
+        .compatible = "fsl,8568-memory-controller",
+        },
+       {},
+};
+
+static struct of_platform_driver mpc85xx_mc_err_driver = {
+       .owner = THIS_MODULE,
+       .name = "mpc85xx_mc_err",
+       .match_table = mpc85xx_mc_err_of_match,
+       .probe = mpc85xx_mc_err_probe,
+       .remove = mpc85xx_mc_err_remove,
+       .driver = {
+                  .name = "mpc85xx_mc_err",
+                  .owner = THIS_MODULE,
+                  },
+};
+
+static int __init mpc85xx_mc_init(void)
+{
+       int res = 0;
+
+       printk(KERN_INFO "Freescale(R) MPC85xx EDAC driver, "
+              "(C) 2006 Montavista Software\n");
+
+       /* make sure error reporting method is sane */
+       switch (edac_op_state) {
+       case EDAC_OPSTATE_POLL:
+       case EDAC_OPSTATE_INT:
+               break;
+       default:
+               edac_op_state = EDAC_OPSTATE_INT;
+               break;
+       }
+
+       res = of_register_platform_driver(&mpc85xx_mc_err_driver);
+       if (res)
+               printk(KERN_WARNING EDAC_MOD_STR "MC fails to register\n");
+
+       res = of_register_platform_driver(&mpc85xx_l2_err_driver);
+       if (res)
+               printk(KERN_WARNING EDAC_MOD_STR "L2 fails to register\n");
+
+#ifdef CONFIG_PCI
+       res = platform_driver_register(&mpc85xx_pci_err_driver);
+       if (res)
+               printk(KERN_WARNING EDAC_MOD_STR "PCI fails to register\n");
+#endif
+
+       /*
+        * need to clear HID1[RFXE] to disable machine check int
+        * so we can catch it
+        */
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               orig_hid1 = mfspr(SPRN_HID1);
+               mtspr(SPRN_HID1, (orig_hid1 & ~0x20000));
+       }
+
+       return 0;
+}
+
+module_init(mpc85xx_mc_init);
+
+static void __exit mpc85xx_mc_exit(void)
+{
+       mtspr(SPRN_HID1, orig_hid1);
+#ifdef CONFIG_PCI
+       platform_driver_unregister(&mpc85xx_pci_err_driver);
+#endif
+       of_unregister_platform_driver(&mpc85xx_l2_err_driver);
+       of_unregister_platform_driver(&mpc85xx_mc_err_driver);
+}
+
+module_exit(mpc85xx_mc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Montavista Software, Inc.");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state,
+                "EDAC Error Reporting state: 0=Poll, 2=Interrupt");
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
new file mode 100644 (file)
index 0000000..135b353
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Freescale MPC85xx Memory Controller kenel module
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#ifndef _MPC85XX_EDAC_H_
+#define _MPC85XX_EDAC_H_
+
+#define MPC85XX_REVISION " Ver: 2.0.0 " __DATE__
+#define EDAC_MOD_STR   "MPC85xx_edac"
+
+#define mpc85xx_printk(level, fmt, arg...) \
+       edac_printk(level, "MPC85xx", fmt, ##arg)
+
+#define mpc85xx_mc_printk(mci, level, fmt, arg...) \
+       edac_mc_chipset_printk(mci, level, "MPC85xx", fmt, ##arg)
+
+/*
+ * DRAM error defines
+ */
+
+/* DDR_SDRAM_CFG */
+#define MPC85XX_MC_DDR_SDRAM_CFG       0x0110
+#define MPC85XX_MC_CS_BNDS_0           0x0000
+#define MPC85XX_MC_CS_BNDS_1           0x0008
+#define MPC85XX_MC_CS_BNDS_2           0x0010
+#define MPC85XX_MC_CS_BNDS_3           0x0018
+#define MPC85XX_MC_CS_BNDS_OFS         0x0008
+
+#define MPC85XX_MC_DATA_ERR_INJECT_HI  0x0e00
+#define MPC85XX_MC_DATA_ERR_INJECT_LO  0x0e04
+#define MPC85XX_MC_ECC_ERR_INJECT      0x0e08
+#define MPC85XX_MC_CAPTURE_DATA_HI     0x0e20
+#define MPC85XX_MC_CAPTURE_DATA_LO     0x0e24
+#define MPC85XX_MC_CAPTURE_ECC         0x0e28
+#define MPC85XX_MC_ERR_DETECT          0x0e40
+#define MPC85XX_MC_ERR_DISABLE         0x0e44
+#define MPC85XX_MC_ERR_INT_EN          0x0e48
+#define MPC85XX_MC_CAPTURE_ATRIBUTES   0x0e4c
+#define MPC85XX_MC_CAPTURE_ADDRESS     0x0e50
+#define MPC85XX_MC_ERR_SBE             0x0e58
+
+#define DSC_MEM_EN     0x80000000
+#define DSC_ECC_EN     0x20000000
+#define DSC_RD_EN      0x10000000
+
+#define DSC_SDTYPE_MASK                0x07000000
+
+#define DSC_SDTYPE_DDR         0x02000000
+#define DSC_SDTYPE_DDR2                0x03000000
+#define DSC_X32_EN     0x00000020
+
+/* Err_Int_En */
+#define DDR_EIE_MSEE   0x1     /* memory select */
+#define DDR_EIE_SBEE   0x4     /* single-bit ECC error */
+#define DDR_EIE_MBEE   0x8     /* multi-bit ECC error */
+
+/* Err_Detect */
+#define DDR_EDE_MSE            0x1     /* memory select */
+#define DDR_EDE_SBE            0x4     /* single-bit ECC error */
+#define DDR_EDE_MBE            0x8     /* multi-bit ECC error */
+#define DDR_EDE_MME            0x80000000      /* multiple memory errors */
+
+/* Err_Disable */
+#define DDR_EDI_MSED   0x1     /* memory select disable */
+#define        DDR_EDI_SBED    0x4     /* single-bit ECC error disable */
+#define        DDR_EDI_MBED    0x8     /* multi-bit ECC error disable */
+
+/*
+ * L2 Err defines
+ */
+#define MPC85XX_L2_ERRINJHI    0x0000
+#define MPC85XX_L2_ERRINJLO    0x0004
+#define MPC85XX_L2_ERRINJCTL   0x0008
+#define MPC85XX_L2_CAPTDATAHI  0x0020
+#define MPC85XX_L2_CAPTDATALO  0x0024
+#define MPC85XX_L2_CAPTECC     0x0028
+#define MPC85XX_L2_ERRDET      0x0040
+#define MPC85XX_L2_ERRDIS      0x0044
+#define MPC85XX_L2_ERRINTEN    0x0048
+#define MPC85XX_L2_ERRATTR     0x004c
+#define MPC85XX_L2_ERRADDR     0x0050
+#define MPC85XX_L2_ERRCTL      0x0058
+
+/* Error Interrupt Enable */
+#define L2_EIE_L2CFGINTEN      0x1
+#define L2_EIE_SBECCINTEN      0x4
+#define L2_EIE_MBECCINTEN      0x8
+#define L2_EIE_TPARINTEN       0x10
+#define L2_EIE_MASK    (L2_EIE_L2CFGINTEN | L2_EIE_SBECCINTEN | \
+                       L2_EIE_MBECCINTEN | L2_EIE_TPARINTEN)
+
+/* Error Detect */
+#define L2_EDE_L2CFGERR                0x1
+#define L2_EDE_SBECCERR                0x4
+#define L2_EDE_MBECCERR                0x8
+#define L2_EDE_TPARERR         0x10
+#define L2_EDE_MULL2ERR                0x80000000
+
+#define L2_EDE_CE_MASK L2_EDE_SBECCERR
+#define L2_EDE_UE_MASK (L2_EDE_L2CFGERR | L2_EDE_MBECCERR | \
+                       L2_EDE_TPARERR)
+#define L2_EDE_MASK    (L2_EDE_L2CFGERR | L2_EDE_SBECCERR | \
+                       L2_EDE_MBECCERR | L2_EDE_TPARERR | L2_EDE_MULL2ERR)
+
+/*
+ * PCI Err defines
+ */
+#define PCI_EDE_TOE                    0x00000001
+#define PCI_EDE_SCM                    0x00000002
+#define PCI_EDE_IRMSV                  0x00000004
+#define PCI_EDE_ORMSV                  0x00000008
+#define PCI_EDE_OWMSV                  0x00000010
+#define PCI_EDE_TGT_ABRT               0x00000020
+#define PCI_EDE_MST_ABRT               0x00000040
+#define PCI_EDE_TGT_PERR               0x00000080
+#define PCI_EDE_MST_PERR               0x00000100
+#define PCI_EDE_RCVD_SERR              0x00000200
+#define PCI_EDE_ADDR_PERR              0x00000400
+#define PCI_EDE_MULTI_ERR              0x80000000
+
+#define PCI_EDE_PERR_MASK      (PCI_EDE_TGT_PERR | PCI_EDE_MST_PERR | \
+                               PCI_EDE_ADDR_PERR)
+
+#define MPC85XX_PCI_ERR_DR             0x0000
+#define MPC85XX_PCI_ERR_CAP_DR         0x0004
+#define MPC85XX_PCI_ERR_EN             0x0008
+#define MPC85XX_PCI_ERR_ATTRIB         0x000c
+#define MPC85XX_PCI_ERR_ADDR           0x0010
+#define MPC85XX_PCI_ERR_EXT_ADDR       0x0014
+#define MPC85XX_PCI_ERR_DL             0x0018
+#define MPC85XX_PCI_ERR_DH             0x001c
+#define MPC85XX_PCI_GAS_TIMR           0x0020
+#define MPC85XX_PCI_PCIX_TIMR          0x0024
+
+struct mpc85xx_mc_pdata {
+       char *name;
+       int edac_idx;
+       void __iomem *mc_vbase;
+       int irq;
+};
+
+struct mpc85xx_l2_pdata {
+       char *name;
+       int edac_idx;
+       void __iomem *l2_vbase;
+       int irq;
+};
+
+struct mpc85xx_pci_pdata {
+       char *name;
+       int edac_idx;
+       void __iomem *pci_vbase;
+       int irq;
+};
+
+#endif
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c
new file mode 100644 (file)
index 0000000..bf071f1
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+ * Marvell MV64x60 Memory Controller kernel module for PPC platforms
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/edac.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+#include "mv64x60_edac.h"
+
+static const char *mv64x60_ctl_name = "MV64x60";
+static int edac_dev_idx;
+static int edac_pci_idx;
+static int edac_mc_idx;
+
+/*********************** PCI err device **********************************/
+#ifdef CONFIG_PCI
+static void mv64x60_pci_check(struct edac_pci_ctl_info *pci)
+{
+       struct mv64x60_pci_pdata *pdata = pci->pvt_info;
+       u32 cause;
+
+       cause = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
+       if (!cause)
+               return;
+
+       printk(KERN_ERR "Error in PCI %d Interface\n", pdata->pci_hose);
+       printk(KERN_ERR "Cause register: 0x%08x\n", cause);
+       printk(KERN_ERR "Address Low: 0x%08x\n",
+              in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_LO));
+       printk(KERN_ERR "Address High: 0x%08x\n",
+              in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_HI));
+       printk(KERN_ERR "Attribute: 0x%08x\n",
+              in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ATTR));
+       printk(KERN_ERR "Command: 0x%08x\n",
+              in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CMD));
+       out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, ~cause);
+
+       if (cause & MV64X60_PCI_PE_MASK)
+               edac_pci_handle_pe(pci, pci->ctl_name);
+
+       if (!(cause & MV64X60_PCI_PE_MASK))
+               edac_pci_handle_npe(pci, pci->ctl_name);
+}
+
+static irqreturn_t mv64x60_pci_isr(int irq, void *dev_id)
+{
+       struct edac_pci_ctl_info *pci = dev_id;
+       struct mv64x60_pci_pdata *pdata = pci->pvt_info;
+       u32 val;
+
+       val = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
+       if (!val)
+               return IRQ_NONE;
+
+       mv64x60_pci_check(pci);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit mv64x60_pci_err_probe(struct platform_device *pdev)
+{
+       struct edac_pci_ctl_info *pci;
+       struct mv64x60_pci_pdata *pdata;
+       struct resource *r;
+       int res = 0;
+
+       if (!devres_open_group(&pdev->dev, mv64x60_pci_err_probe, GFP_KERNEL))
+               return -ENOMEM;
+
+       pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mv64x60_pci_err");
+       if (!pci)
+               return -ENOMEM;
+
+       pdata = pci->pvt_info;
+
+       pdata->pci_hose = pdev->id;
+       pdata->name = "mpc85xx_pci_err";
+       pdata->irq = NO_IRQ;
+       platform_set_drvdata(pdev, pci);
+       pci->dev = &pdev->dev;
+       pci->dev_name = pdev->dev.bus_id;
+       pci->mod_name = EDAC_MOD_STR;
+       pci->ctl_name = pdata->name;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               pci->edac_check = mv64x60_pci_check;
+
+       pdata->edac_idx = edac_pci_idx++;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               printk(KERN_ERR "%s: Unable to get resource for "
+                      "PCI err regs\n", __func__);
+               res = -ENOENT;
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev,
+                                    r->start,
+                                    r->end - r->start + 1,
+                                    pdata->name)) {
+               printk(KERN_ERR "%s: Error while requesting mem region\n",
+                      __func__);
+               res = -EBUSY;
+               goto err;
+       }
+
+       pdata->pci_vbase = devm_ioremap(&pdev->dev,
+                                       r->start,
+                                       r->end - r->start + 1);
+       if (!pdata->pci_vbase) {
+               printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
+               res = -ENOMEM;
+               goto err;
+       }
+
+       out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, 0);
+       out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK, 0);
+       out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK,
+                MV64X60_PCIx_ERR_MASK_VAL);
+
+       if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
+               debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+               goto err;
+       }
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               pdata->irq = platform_get_irq(pdev, 0);
+               res = devm_request_irq(&pdev->dev,
+                                      pdata->irq,
+                                      mv64x60_pci_isr,
+                                      IRQF_DISABLED,
+                                      "[EDAC] PCI err",
+                                      pci);
+               if (res < 0) {
+                       printk(KERN_ERR "%s: Unable to request irq %d for "
+                              "MV64x60 PCI ERR\n", __func__, pdata->irq);
+                       res = -ENODEV;
+                       goto err2;
+               }
+               printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n",
+                      pdata->irq);
+       }
+
+       devres_remove_group(&pdev->dev, mv64x60_pci_err_probe);
+
+       /* get this far and it's successful */
+       debugf3("%s(): success\n", __func__);
+
+       return 0;
+
+err2:
+       edac_pci_del_device(&pdev->dev);
+err:
+       edac_pci_free_ctl_info(pci);
+       devres_release_group(&pdev->dev, mv64x60_pci_err_probe);
+       return res;
+}
+
+static int mv64x60_pci_err_remove(struct platform_device *pdev)
+{
+       struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
+
+       debugf0("%s()\n", __func__);
+
+       edac_pci_del_device(&pdev->dev);
+
+       edac_pci_free_ctl_info(pci);
+
+       return 0;
+}
+
+static struct platform_driver mv64x60_pci_err_driver = {
+       .probe = mv64x60_pci_err_probe,
+       .remove = __devexit_p(mv64x60_pci_err_remove),
+       .driver = {
+                  .name = "mv64x60_pci_err",
+       }
+};
+
+#endif /* CONFIG_PCI */
+
+/*********************** SRAM err device **********************************/
+static void mv64x60_sram_check(struct edac_device_ctl_info *edac_dev)
+{
+       struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info;
+       u32 cause;
+
+       cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
+       if (!cause)
+               return;
+
+       printk(KERN_ERR "Error in internal SRAM\n");
+       printk(KERN_ERR "Cause register: 0x%08x\n", cause);
+       printk(KERN_ERR "Address Low: 0x%08x\n",
+              in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_LO));
+       printk(KERN_ERR "Address High: 0x%08x\n",
+              in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_HI));
+       printk(KERN_ERR "Data Low: 0x%08x\n",
+              in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_LO));
+       printk(KERN_ERR "Data High: 0x%08x\n",
+              in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_HI));
+       printk(KERN_ERR "Parity: 0x%08x\n",
+              in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_PARITY));
+       out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0);
+
+       edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
+}
+
+static irqreturn_t mv64x60_sram_isr(int irq, void *dev_id)
+{
+       struct edac_device_ctl_info *edac_dev = dev_id;
+       struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info;
+       u32 cause;
+
+       cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
+       if (!cause)
+               return IRQ_NONE;
+
+       mv64x60_sram_check(edac_dev);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit mv64x60_sram_err_probe(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *edac_dev;
+       struct mv64x60_sram_pdata *pdata;
+       struct resource *r;
+       int res = 0;
+
+       if (!devres_open_group(&pdev->dev, mv64x60_sram_err_probe, GFP_KERNEL))
+               return -ENOMEM;
+
+       edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
+                                             "sram", 1, NULL, 0, 0, NULL, 0,
+                                             edac_dev_idx);
+       if (!edac_dev) {
+               devres_release_group(&pdev->dev, mv64x60_sram_err_probe);
+               return -ENOMEM;
+       }
+
+       pdata = edac_dev->pvt_info;
+       pdata->name = "mv64x60_sram_err";
+       pdata->irq = NO_IRQ;
+       edac_dev->dev = &pdev->dev;
+       platform_set_drvdata(pdev, edac_dev);
+       edac_dev->dev_name = pdev->dev.bus_id;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               printk(KERN_ERR "%s: Unable to get resource for "
+                      "SRAM err regs\n", __func__);
+               res = -ENOENT;
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev,
+                                    r->start,
+                                    r->end - r->start + 1,
+                                    pdata->name)) {
+               printk(KERN_ERR "%s: Error while request mem region\n",
+                      __func__);
+               res = -EBUSY;
+               goto err;
+       }
+
+       pdata->sram_vbase = devm_ioremap(&pdev->dev,
+                                        r->start,
+                                        r->end - r->start + 1);
+       if (!pdata->sram_vbase) {
+               printk(KERN_ERR "%s: Unable to setup SRAM err regs\n",
+                      __func__);
+               res = -ENOMEM;
+               goto err;
+       }
+
+       /* setup SRAM err registers */
+       out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0);
+
+       edac_dev->mod_name = EDAC_MOD_STR;
+       edac_dev->ctl_name = pdata->name;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               edac_dev->edac_check = mv64x60_sram_check;
+
+       pdata->edac_idx = edac_dev_idx++;
+
+       if (edac_device_add_device(edac_dev) > 0) {
+               debugf3("%s(): failed edac_device_add_device()\n", __func__);
+               goto err;
+       }
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               pdata->irq = platform_get_irq(pdev, 0);
+               res = devm_request_irq(&pdev->dev,
+                                      pdata->irq,
+                                      mv64x60_sram_isr,
+                                      IRQF_DISABLED,
+                                      "[EDAC] SRAM err",
+                                      edac_dev);
+               if (res < 0) {
+                       printk(KERN_ERR
+                              "%s: Unable to request irq %d for "
+                              "MV64x60 SRAM ERR\n", __func__, pdata->irq);
+                       res = -ENODEV;
+                       goto err2;
+               }
+
+               printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for SRAM Err\n",
+                      pdata->irq);
+       }
+
+       devres_remove_group(&pdev->dev, mv64x60_sram_err_probe);
+
+       /* get this far and it's successful */
+       debugf3("%s(): success\n", __func__);
+
+       return 0;
+
+err2:
+       edac_device_del_device(&pdev->dev);
+err:
+       devres_release_group(&pdev->dev, mv64x60_sram_err_probe);
+       edac_device_free_ctl_info(edac_dev);
+       return res;
+}
+
+static int mv64x60_sram_err_remove(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
+
+       debugf0("%s()\n", __func__);
+
+       edac_device_del_device(&pdev->dev);
+       edac_device_free_ctl_info(edac_dev);
+
+       return 0;
+}
+
+static struct platform_driver mv64x60_sram_err_driver = {
+       .probe = mv64x60_sram_err_probe,
+       .remove = mv64x60_sram_err_remove,
+       .driver = {
+                  .name = "mv64x60_sram_err",
+       }
+};
+
+/*********************** CPU err device **********************************/
+static void mv64x60_cpu_check(struct edac_device_ctl_info *edac_dev)
+{
+       struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info;
+       u32 cause;
+
+       cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) &
+           MV64x60_CPU_CAUSE_MASK;
+       if (!cause)
+               return;
+
+       printk(KERN_ERR "Error on CPU interface\n");
+       printk(KERN_ERR "Cause register: 0x%08x\n", cause);
+       printk(KERN_ERR "Address Low: 0x%08x\n",
+              in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_LO));
+       printk(KERN_ERR "Address High: 0x%08x\n",
+              in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_HI));
+       printk(KERN_ERR "Data Low: 0x%08x\n",
+              in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_LO));
+       printk(KERN_ERR "Data High: 0x%08x\n",
+              in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_HI));
+       printk(KERN_ERR "Parity: 0x%08x\n",
+              in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_PARITY));
+       out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0);
+
+       edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
+}
+
+static irqreturn_t mv64x60_cpu_isr(int irq, void *dev_id)
+{
+       struct edac_device_ctl_info *edac_dev = dev_id;
+       struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info;
+       u32 cause;
+
+       cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) &
+           MV64x60_CPU_CAUSE_MASK;
+       if (!cause)
+               return IRQ_NONE;
+
+       mv64x60_cpu_check(edac_dev);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *edac_dev;
+       struct resource *r;
+       struct mv64x60_cpu_pdata *pdata;
+       int res = 0;
+
+       if (!devres_open_group(&pdev->dev, mv64x60_cpu_err_probe, GFP_KERNEL))
+               return -ENOMEM;
+
+       edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
+                                             "cpu", 1, NULL, 0, 0, NULL, 0,
+                                             edac_dev_idx);
+       if (!edac_dev) {
+               devres_release_group(&pdev->dev, mv64x60_cpu_err_probe);
+               return -ENOMEM;
+       }
+
+       pdata = edac_dev->pvt_info;
+       pdata->name = "mv64x60_cpu_err";
+       pdata->irq = NO_IRQ;
+       edac_dev->dev = &pdev->dev;
+       platform_set_drvdata(pdev, edac_dev);
+       edac_dev->dev_name = pdev->dev.bus_id;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               printk(KERN_ERR "%s: Unable to get resource for "
+                      "CPU err regs\n", __func__);
+               res = -ENOENT;
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev,
+                                    r->start,
+                                    r->end - r->start + 1,
+                                    pdata->name)) {
+               printk(KERN_ERR "%s: Error while requesting mem region\n",
+                      __func__);
+               res = -EBUSY;
+               goto err;
+       }
+
+       pdata->cpu_vbase[0] = devm_ioremap(&pdev->dev,
+                                          r->start,
+                                          r->end - r->start + 1);
+       if (!pdata->cpu_vbase[0]) {
+               printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__);
+               res = -ENOMEM;
+               goto err;
+       }
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!r) {
+               printk(KERN_ERR "%s: Unable to get resource for "
+                      "CPU err regs\n", __func__);
+               res = -ENOENT;
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev,
+                                    r->start,
+                                    r->end - r->start + 1,
+                                    pdata->name)) {
+               printk(KERN_ERR "%s: Error while requesting mem region\n",
+                      __func__);
+               res = -EBUSY;
+               goto err;
+       }
+
+       pdata->cpu_vbase[1] = devm_ioremap(&pdev->dev,
+                                          r->start,
+                                          r->end - r->start + 1);
+       if (!pdata->cpu_vbase[1]) {
+               printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__);
+               res = -ENOMEM;
+               goto err;
+       }
+
+       /* setup CPU err registers */
+       out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0);
+       out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0);
+       out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0x000000ff);
+
+       edac_dev->mod_name = EDAC_MOD_STR;
+       edac_dev->ctl_name = pdata->name;
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               edac_dev->edac_check = mv64x60_cpu_check;
+
+       pdata->edac_idx = edac_dev_idx++;
+
+       if (edac_device_add_device(edac_dev) > 0) {
+               debugf3("%s(): failed edac_device_add_device()\n", __func__);
+               goto err;
+       }
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               pdata->irq = platform_get_irq(pdev, 0);
+               res = devm_request_irq(&pdev->dev,
+                                      pdata->irq,
+                                      mv64x60_cpu_isr,
+                                      IRQF_DISABLED,
+                                      "[EDAC] CPU err",
+                                      edac_dev);
+               if (res < 0) {
+                       printk(KERN_ERR
+                              "%s: Unable to request irq %d for MV64x60 "
+                              "CPU ERR\n", __func__, pdata->irq);
+                       res = -ENODEV;
+                       goto err2;
+               }
+
+               printk(KERN_INFO EDAC_MOD_STR
+                      " acquired irq %d for CPU Err\n", pdata->irq);
+       }
+
+       devres_remove_group(&pdev->dev, mv64x60_cpu_err_probe);
+
+       /* get this far and it's successful */
+       debugf3("%s(): success\n", __func__);
+
+       return 0;
+
+err2:
+       edac_device_del_device(&pdev->dev);
+err:
+       devres_release_group(&pdev->dev, mv64x60_cpu_err_probe);
+       edac_device_free_ctl_info(edac_dev);
+       return res;
+}
+
+static int mv64x60_cpu_err_remove(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
+
+       debugf0("%s()\n", __func__);
+
+       edac_device_del_device(&pdev->dev);
+       edac_device_free_ctl_info(edac_dev);
+       return 0;
+}
+
+static struct platform_driver mv64x60_cpu_err_driver = {
+       .probe = mv64x60_cpu_err_probe,
+       .remove = mv64x60_cpu_err_remove,
+       .driver = {
+                  .name = "mv64x60_cpu_err",
+       }
+};
+
+/*********************** DRAM err device **********************************/
+
+static void mv64x60_mc_check(struct mem_ctl_info *mci)
+{
+       struct mv64x60_mc_pdata *pdata = mci->pvt_info;
+       u32 reg;
+       u32 err_addr;
+       u32 sdram_ecc;
+       u32 comp_ecc;
+       u32 syndrome;
+
+       reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
+       if (!reg)
+               return;
+
+       err_addr = reg & ~0x3;
+       sdram_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_RCVD);
+       comp_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CALC);
+       syndrome = sdram_ecc ^ comp_ecc;
+
+       /* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */
+       if (!(reg & 0x1))
+               edac_mc_handle_ce(mci, err_addr >> PAGE_SHIFT,
+                                 err_addr & PAGE_MASK, syndrome, 0, 0,
+                                 mci->ctl_name);
+       else    /* 2 bit error, UE */
+               edac_mc_handle_ue(mci, err_addr >> PAGE_SHIFT,
+                                 err_addr & PAGE_MASK, 0, mci->ctl_name);
+
+       /* clear the error */
+       out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
+}
+
+static irqreturn_t mv64x60_mc_isr(int irq, void *dev_id)
+{
+       struct mem_ctl_info *mci = dev_id;
+       struct mv64x60_mc_pdata *pdata = mci->pvt_info;
+       u32 reg;
+
+       reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
+       if (!reg)
+               return IRQ_NONE;
+
+       /* writing 0's to the ECC err addr in check function clears irq */
+       mv64x60_mc_check(mci);
+
+       return IRQ_HANDLED;
+}
+
+static void get_total_mem(struct mv64x60_mc_pdata *pdata)
+{
+       struct device_node *np = NULL;
+       const unsigned int *reg;
+
+       np = of_find_node_by_type(NULL, "memory");
+       if (!np)
+               return;
+
+       reg = get_property(np, "reg", NULL);
+
+       pdata->total_mem = reg[1];
+}
+
+static void mv64x60_init_csrows(struct mem_ctl_info *mci,
+                               struct mv64x60_mc_pdata *pdata)
+{
+       struct csrow_info *csrow;
+       u32 devtype;
+       u32 ctl;
+
+       get_total_mem(pdata);
+
+       ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
+
+       csrow = &mci->csrows[0];
+       csrow->first_page = 0;
+       csrow->nr_pages = pdata->total_mem >> PAGE_SHIFT;
+       csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
+       csrow->grain = 8;
+
+       csrow->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR;
+
+       devtype = (ctl >> 20) & 0x3;
+       switch (devtype) {
+       case 0x0:
+               csrow->dtype = DEV_X32;
+               break;
+       case 0x2:               /* could be X8 too, but no way to tell */
+               csrow->dtype = DEV_X16;
+               break;
+       case 0x3:
+               csrow->dtype = DEV_X4;
+               break;
+       default:
+               csrow->dtype = DEV_UNKNOWN;
+               break;
+       }
+
+       csrow->edac_mode = EDAC_SECDED;
+}
+
+static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
+{
+       struct mem_ctl_info *mci;
+       struct mv64x60_mc_pdata *pdata;
+       struct resource *r;
+       u32 ctl;
+       int res = 0;
+
+       if (!devres_open_group(&pdev->dev, mv64x60_mc_err_probe, GFP_KERNEL))
+               return -ENOMEM;
+
+       mci = edac_mc_alloc(sizeof(struct mv64x60_mc_pdata), 1, 1, edac_mc_idx);
+       if (!mci) {
+               printk(KERN_ERR "%s: No memory for CPU err\n", __func__);
+               devres_release_group(&pdev->dev, mv64x60_mc_err_probe);
+               return -ENOMEM;
+       }
+
+       pdata = mci->pvt_info;
+       mci->dev = &pdev->dev;
+       platform_set_drvdata(pdev, mci);
+       pdata->name = "mv64x60_mc_err";
+       pdata->irq = NO_IRQ;
+       mci->dev_name = pdev->dev.bus_id;
+       pdata->edac_idx = edac_mc_idx++;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               printk(KERN_ERR "%s: Unable to get resource for "
+                      "MC err regs\n", __func__);
+               res = -ENOENT;
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev,
+                                    r->start,
+                                    r->end - r->start + 1,
+                                    pdata->name)) {
+               printk(KERN_ERR "%s: Error while requesting mem region\n",
+                      __func__);
+               res = -EBUSY;
+               goto err;
+       }
+
+       pdata->mc_vbase = devm_ioremap(&pdev->dev,
+                                      r->start,
+                                      r->end - r->start + 1);
+       if (!pdata->mc_vbase) {
+               printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__);
+               res = -ENOMEM;
+               goto err;
+       }
+
+       ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
+       if (!(ctl & MV64X60_SDRAM_ECC)) {
+               /* Non-ECC RAM? */
+               printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__);
+               res = -ENODEV;
+               goto err2;
+       }
+
+       debugf3("%s(): init mci\n", __func__);
+       mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+       mci->edac_cap = EDAC_FLAG_SECDED;
+       mci->mod_name = EDAC_MOD_STR;
+       mci->mod_ver = MV64x60_REVISION;
+       mci->ctl_name = mv64x60_ctl_name;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               mci->edac_check = mv64x60_mc_check;
+
+       mci->ctl_page_to_phys = NULL;
+
+       mci->scrub_mode = SCRUB_SW_SRC;
+
+       mv64x60_init_csrows(mci, pdata);
+
+       /* setup MC registers */
+       out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
+       ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL);
+       ctl = (ctl & 0xff00ffff) | 0x10000;
+       out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL, ctl);
+
+       if (edac_mc_add_mc(mci)) {
+               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               goto err;
+       }
+
+       if (edac_op_state == EDAC_OPSTATE_INT) {
+               /* acquire interrupt that reports errors */
+               pdata->irq = platform_get_irq(pdev, 0);
+               res = devm_request_irq(&pdev->dev,
+                                      pdata->irq,
+                                      mv64x60_mc_isr,
+                                      IRQF_DISABLED,
+                                      "[EDAC] MC err",
+                                      mci);
+               if (res < 0) {
+                       printk(KERN_ERR "%s: Unable to request irq %d for "
+                              "MV64x60 DRAM ERR\n", __func__, pdata->irq);
+                       res = -ENODEV;
+                       goto err2;
+               }
+
+               printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for MC Err\n",
+                      pdata->irq);
+       }
+
+       /* get this far and it's successful */
+       debugf3("%s(): success\n", __func__);
+
+       return 0;
+
+err2:
+       edac_mc_del_mc(&pdev->dev);
+err:
+       devres_release_group(&pdev->dev, mv64x60_mc_err_probe);
+       edac_mc_free(mci);
+       return res;
+}
+
+static int mv64x60_mc_err_remove(struct platform_device *pdev)
+{
+       struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+       debugf0("%s()\n", __func__);
+
+       edac_mc_del_mc(&pdev->dev);
+       edac_mc_free(mci);
+       return 0;
+}
+
+static struct platform_driver mv64x60_mc_err_driver = {
+       .probe = mv64x60_mc_err_probe,
+       .remove = mv64x60_mc_err_remove,
+       .driver = {
+                  .name = "mv64x60_mc_err",
+       }
+};
+
+static int __init mv64x60_edac_init(void)
+{
+       int ret = 0;
+
+       printk(KERN_INFO "Marvell MV64x60 EDAC driver " MV64x60_REVISION "\n");
+       printk(KERN_INFO "\t(C) 2006-2007 MontaVista Software\n");
+       /* make sure error reporting method is sane */
+       switch (edac_op_state) {
+       case EDAC_OPSTATE_POLL:
+       case EDAC_OPSTATE_INT:
+               break;
+       default:
+               edac_op_state = EDAC_OPSTATE_INT;
+               break;
+       }
+
+       ret = platform_driver_register(&mv64x60_mc_err_driver);
+       if (ret)
+               printk(KERN_WARNING EDAC_MOD_STR "MC err failed to register\n");
+
+       ret = platform_driver_register(&mv64x60_cpu_err_driver);
+       if (ret)
+               printk(KERN_WARNING EDAC_MOD_STR
+                       "CPU err failed to register\n");
+
+       ret = platform_driver_register(&mv64x60_sram_err_driver);
+       if (ret)
+               printk(KERN_WARNING EDAC_MOD_STR
+                       "SRAM err failed to register\n");
+
+#ifdef CONFIG_PCI
+       ret = platform_driver_register(&mv64x60_pci_err_driver);
+       if (ret)
+               printk(KERN_WARNING EDAC_MOD_STR
+                       "PCI err failed to register\n");
+#endif
+
+       return ret;
+}
+module_init(mv64x60_edac_init);
+
+static void __exit mv64x60_edac_exit(void)
+{
+#ifdef CONFIG_PCI
+       platform_driver_unregister(&mv64x60_pci_err_driver);
+#endif
+       platform_driver_unregister(&mv64x60_sram_err_driver);
+       platform_driver_unregister(&mv64x60_cpu_err_driver);
+       platform_driver_unregister(&mv64x60_mc_err_driver);
+}
+module_exit(mv64x60_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Montavista Software, Inc.");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state,
+                "EDAC Error Reporting state: 0=Poll, 2=Interrupt");
diff --git a/drivers/edac/mv64x60_edac.h b/drivers/edac/mv64x60_edac.h
new file mode 100644 (file)
index 0000000..e042e2d
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * EDAC defs for Marvell MV64x60 bridge chip
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#ifndef _MV64X60_EDAC_H_
+#define _MV64X60_EDAC_H_
+
+#define MV64x60_REVISION " Ver: 2.0.0 " __DATE__
+#define EDAC_MOD_STR   "MV64x60_edac"
+
+#define mv64x60_printk(level, fmt, arg...) \
+       edac_printk(level, "MV64x60", fmt, ##arg)
+
+#define mv64x60_mc_printk(mci, level, fmt, arg...) \
+       edac_mc_chipset_printk(mci, level, "MV64x60", fmt, ##arg)
+
+/* CPU Error Report Registers */
+#define MV64x60_CPU_ERR_ADDR_LO                0x00    /* 0x0070 */
+#define MV64x60_CPU_ERR_ADDR_HI                0x08    /* 0x0078 */
+#define MV64x60_CPU_ERR_DATA_LO                0x00    /* 0x0128 */
+#define MV64x60_CPU_ERR_DATA_HI                0x08    /* 0x0130 */
+#define MV64x60_CPU_ERR_PARITY         0x10    /* 0x0138 */
+#define MV64x60_CPU_ERR_CAUSE          0x18    /* 0x0140 */
+#define MV64x60_CPU_ERR_MASK           0x20    /* 0x0148 */
+
+#define MV64x60_CPU_CAUSE_MASK         0x07ffffff
+
+/* SRAM Error Report Registers */
+#define MV64X60_SRAM_ERR_CAUSE         0x08    /* 0x0388 */
+#define MV64X60_SRAM_ERR_ADDR_LO       0x10    /* 0x0390 */
+#define MV64X60_SRAM_ERR_ADDR_HI       0x78    /* 0x03f8 */
+#define MV64X60_SRAM_ERR_DATA_LO       0x18    /* 0x0398 */
+#define MV64X60_SRAM_ERR_DATA_HI       0x20    /* 0x03a0 */
+#define MV64X60_SRAM_ERR_PARITY                0x28    /* 0x03a8 */
+
+/* SDRAM Controller Registers */
+#define MV64X60_SDRAM_CONFIG           0x00    /* 0x1400 */
+#define MV64X60_SDRAM_ERR_DATA_HI      0x40    /* 0x1440 */
+#define MV64X60_SDRAM_ERR_DATA_LO      0x44    /* 0x1444 */
+#define MV64X60_SDRAM_ERR_ECC_RCVD     0x48    /* 0x1448 */
+#define MV64X60_SDRAM_ERR_ECC_CALC     0x4c    /* 0x144c */
+#define MV64X60_SDRAM_ERR_ADDR         0x50    /* 0x1450 */
+#define MV64X60_SDRAM_ERR_ECC_CNTL     0x54    /* 0x1454 */
+#define MV64X60_SDRAM_ERR_ECC_ERR_CNT  0x58    /* 0x1458 */
+
+#define MV64X60_SDRAM_REGISTERED       0x20000
+#define MV64X60_SDRAM_ECC              0x40000
+
+#ifdef CONFIG_PCI
+/*
+ * Bit 0 of MV64x60_PCIx_ERR_MASK does not exist on the 64360 and because of
+ * errata FEr-#11 and FEr-##16 for the 64460, it should be 0 on that chip as
+ * well.  IOW, don't set bit 0.
+ */
+#define MV64X60_PCIx_ERR_MASK_VAL      0x00a50c24
+
+/* Register offsets from PCIx error address low register */
+#define MV64X60_PCI_ERROR_ADDR_LO      0x00
+#define MV64X60_PCI_ERROR_ADDR_HI      0x04
+#define MV64X60_PCI_ERROR_ATTR         0x08
+#define MV64X60_PCI_ERROR_CMD          0x10
+#define MV64X60_PCI_ERROR_CAUSE                0x18
+#define MV64X60_PCI_ERROR_MASK         0x1c
+
+#define MV64X60_PCI_ERR_SWrPerr                0x0002
+#define MV64X60_PCI_ERR_SRdPerr                0x0004
+#define        MV64X60_PCI_ERR_MWrPerr         0x0020
+#define MV64X60_PCI_ERR_MRdPerr                0x0040
+
+#define MV64X60_PCI_PE_MASK    (MV64X60_PCI_ERR_SWrPerr | \
+                               MV64X60_PCI_ERR_SRdPerr | \
+                               MV64X60_PCI_ERR_MWrPerr | \
+                               MV64X60_PCI_ERR_MRdPerr)
+
+struct mv64x60_pci_pdata {
+       int pci_hose;
+       void __iomem *pci_vbase;
+       char *name;
+       int irq;
+       int edac_idx;
+};
+
+#endif                         /* CONFIG_PCI */
+
+struct mv64x60_mc_pdata {
+       void __iomem *mc_vbase;
+       int total_mem;
+       char *name;
+       int irq;
+       int edac_idx;
+};
+
+struct mv64x60_cpu_pdata {
+       void __iomem *cpu_vbase[2];
+       char *name;
+       int irq;
+       int edac_idx;
+};
+
+struct mv64x60_sram_pdata {
+       void __iomem *sram_vbase;
+       char *name;
+       int irq;
+       int edac_idx;
+};
+
+#endif
index 18cdcb3ae1ca3d11131b0cf9498086a25066ec14..1636806ec55e8432af872e6327ef02b297db795c 100644 (file)
@@ -658,4 +658,5 @@ MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_AUTHOR("Dell Inc.");
 MODULE_LICENSE("GPL");
-
+/* Any System or BIOS claiming to be by Dell */
+MODULE_ALIAS("dmi:*:[bs]vnD[Ee][Ll][Ll]*:*");
index 313c99cbdc62363632217d3061b7709b972b2127..e880d6c8d8965d88e9fcc9674006cf6b4206a215 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/dmi.h>
 #include <linux/device.h>
-#include <linux/autoconf.h>
 
 struct dmi_device_attribute{
        struct device_attribute dev_attr;
index 74fac0f5c348902a7ed9355ae746a6e946fdc8b3..bbd28342e771f415a4b7365653e3383757a398a2 100644 (file)
@@ -27,15 +27,16 @@ config DEBUG_GPIO
 
 comment "I2C GPIO expanders:"
 
-config GPIO_PCA9539
-       tristate "PCA9539 16-bit I/O port"
+config GPIO_PCA953X
+       tristate "PCA953x I/O ports"
        depends on I2C
        help
-         Say yes here to support the PCA9539 16-bit I/O port. These
-         parts are made by NXP and TI.
+         Say yes here to support the PCA9534 (8-bit), PCA9535 (16-bit),
+         PCA9536 (4-bit), PCA9537 (4-bit), PCA9538 (8-bit), and PCA9539
+         (16-bit) I/O ports. These parts are made by NXP and TI.
 
          This driver can also be built as a module.  If so, the module
-         will be called pca9539.
+         will be called pca953x.
 
 config GPIO_PCF857X
        tristate "PCF857x, PCA857x, and PCA967x I2C GPIO expanders"
index 470ecd6aa778ee3c132fff431e513df80ef4c3a1..fdde9923cf332e67fbab712cf110ddabdc7beebe 100644 (file)
@@ -5,5 +5,5 @@ ccflags-$(CONFIG_DEBUG_GPIO)    += -DDEBUG
 obj-$(CONFIG_HAVE_GPIO_LIB)    += gpiolib.o
 
 obj-$(CONFIG_GPIO_MCP23S08)    += mcp23s08.o
-obj-$(CONFIG_GPIO_PCA9539)     += pca9539.o
+obj-$(CONFIG_GPIO_PCA953X)     += pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)     += pcf857x.o
diff --git a/drivers/gpio/pca9539.c b/drivers/gpio/pca9539.c
deleted file mode 100644 (file)
index 3e85c92..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- *  pca9539.c - 16-bit I/O port with interrupt and reset
- *
- *  Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
- *  Copyright (C) 2007 Marvell International Ltd.
- *
- *  Derived from drivers/i2c/chips/pca9539.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; version 2 of the License.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/i2c/pca9539.h>
-
-#include <asm/gpio.h>
-
-
-#define NR_PCA9539_GPIOS       16
-
-#define PCA9539_INPUT          0
-#define PCA9539_OUTPUT         2
-#define PCA9539_INVERT         4
-#define PCA9539_DIRECTION      6
-
-struct pca9539_chip {
-       unsigned gpio_start;
-       uint16_t reg_output;
-       uint16_t reg_direction;
-
-       struct i2c_client *client;
-       struct gpio_chip gpio_chip;
-};
-
-/* NOTE:  we can't currently rely on fault codes to come from SMBus
- * calls, so we map all errors to EIO here and return zero otherwise.
- */
-static int pca9539_write_reg(struct pca9539_chip *chip, int reg, uint16_t val)
-{
-       if (i2c_smbus_write_word_data(chip->client, reg, val) < 0)
-               return -EIO;
-       else
-               return 0;
-}
-
-static int pca9539_read_reg(struct pca9539_chip *chip, int reg, uint16_t *val)
-{
-       int ret;
-
-       ret = i2c_smbus_read_word_data(chip->client, reg);
-       if (ret < 0) {
-               dev_err(&chip->client->dev, "failed reading register\n");
-               return -EIO;
-       }
-
-       *val = (uint16_t)ret;
-       return 0;
-}
-
-static int pca9539_gpio_direction_input(struct gpio_chip *gc, unsigned off)
-{
-       struct pca9539_chip *chip;
-       uint16_t reg_val;
-       int ret;
-
-       chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
-       reg_val = chip->reg_direction | (1u << off);
-       ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
-       if (ret)
-               return ret;
-
-       chip->reg_direction = reg_val;
-       return 0;
-}
-
-static int pca9539_gpio_direction_output(struct gpio_chip *gc,
-               unsigned off, int val)
-{
-       struct pca9539_chip *chip;
-       uint16_t reg_val;
-       int ret;
-
-       chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
-       /* set output level */
-       if (val)
-               reg_val = chip->reg_output | (1u << off);
-       else
-               reg_val = chip->reg_output & ~(1u << off);
-
-       ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
-       if (ret)
-               return ret;
-
-       chip->reg_output = reg_val;
-
-       /* then direction */
-       reg_val = chip->reg_direction & ~(1u << off);
-       ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
-       if (ret)
-               return ret;
-
-       chip->reg_direction = reg_val;
-       return 0;
-}
-
-static int pca9539_gpio_get_value(struct gpio_chip *gc, unsigned off)
-{
-       struct pca9539_chip *chip;
-       uint16_t reg_val;
-       int ret;
-
-       chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
-       ret = pca9539_read_reg(chip, PCA9539_INPUT, &reg_val);
-       if (ret < 0) {
-               /* NOTE:  diagnostic already emitted; that's all we should
-                * do unless gpio_*_value_cansleep() calls become different
-                * from their nonsleeping siblings (and report faults).
-                */
-               return 0;
-       }
-
-       return (reg_val & (1u << off)) ? 1 : 0;
-}
-
-static void pca9539_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
-{
-       struct pca9539_chip *chip;
-       uint16_t reg_val;
-       int ret;
-
-       chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
-       if (val)
-               reg_val = chip->reg_output | (1u << off);
-       else
-               reg_val = chip->reg_output & ~(1u << off);
-
-       ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
-       if (ret)
-               return;
-
-       chip->reg_output = reg_val;
-}
-
-static int pca9539_init_gpio(struct pca9539_chip *chip)
-{
-       struct gpio_chip *gc;
-
-       gc = &chip->gpio_chip;
-
-       gc->direction_input  = pca9539_gpio_direction_input;
-       gc->direction_output = pca9539_gpio_direction_output;
-       gc->get = pca9539_gpio_get_value;
-       gc->set = pca9539_gpio_set_value;
-
-       gc->base = chip->gpio_start;
-       gc->ngpio = NR_PCA9539_GPIOS;
-       gc->label = "pca9539";
-
-       return gpiochip_add(gc);
-}
-
-static int __devinit pca9539_probe(struct i2c_client *client)
-{
-       struct pca9539_platform_data *pdata;
-       struct pca9539_chip *chip;
-       int ret;
-
-       pdata = client->dev.platform_data;
-       if (pdata == NULL)
-               return -ENODEV;
-
-       chip = kzalloc(sizeof(struct pca9539_chip), GFP_KERNEL);
-       if (chip == NULL)
-               return -ENOMEM;
-
-       chip->client = client;
-
-       chip->gpio_start = pdata->gpio_base;
-
-       /* initialize cached registers from their original values.
-        * we can't share this chip with another i2c master.
-        */
-       ret = pca9539_read_reg(chip, PCA9539_OUTPUT, &chip->reg_output);
-       if (ret)
-               goto out_failed;
-
-       ret = pca9539_read_reg(chip, PCA9539_DIRECTION, &chip->reg_direction);
-       if (ret)
-               goto out_failed;
-
-       /* set platform specific polarity inversion */
-       ret = pca9539_write_reg(chip, PCA9539_INVERT, pdata->invert);
-       if (ret)
-               goto out_failed;
-
-       ret = pca9539_init_gpio(chip);
-       if (ret)
-               goto out_failed;
-
-       if (pdata->setup) {
-               ret = pdata->setup(client, chip->gpio_chip.base,
-                               chip->gpio_chip.ngpio, pdata->context);
-               if (ret < 0)
-                       dev_warn(&client->dev, "setup failed, %d\n", ret);
-       }
-
-       i2c_set_clientdata(client, chip);
-       return 0;
-
-out_failed:
-       kfree(chip);
-       return ret;
-}
-
-static int pca9539_remove(struct i2c_client *client)
-{
-       struct pca9539_platform_data *pdata = client->dev.platform_data;
-       struct pca9539_chip *chip = i2c_get_clientdata(client);
-       int ret = 0;
-
-       if (pdata->teardown) {
-               ret = pdata->teardown(client, chip->gpio_chip.base,
-                               chip->gpio_chip.ngpio, pdata->context);
-               if (ret < 0) {
-                       dev_err(&client->dev, "%s failed, %d\n",
-                                       "teardown", ret);
-                       return ret;
-               }
-       }
-
-       ret = gpiochip_remove(&chip->gpio_chip);
-       if (ret) {
-               dev_err(&client->dev, "%s failed, %d\n",
-                               "gpiochip_remove()", ret);
-               return ret;
-       }
-
-       kfree(chip);
-       return 0;
-}
-
-static struct i2c_driver pca9539_driver = {
-       .driver = {
-               .name   = "pca9539",
-       },
-       .probe          = pca9539_probe,
-       .remove         = pca9539_remove,
-};
-
-static int __init pca9539_init(void)
-{
-       return i2c_add_driver(&pca9539_driver);
-}
-module_init(pca9539_init);
-
-static void __exit pca9539_exit(void)
-{
-       i2c_del_driver(&pca9539_driver);
-}
-module_exit(pca9539_exit);
-
-MODULE_AUTHOR("eric miao <eric.miao@marvell.com>");
-MODULE_DESCRIPTION("GPIO expander driver for PCA9539");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
new file mode 100644 (file)
index 0000000..92583cd
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ *  pca953x.c - 4/8/16 bit I/O ports
+ *
+ *  Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
+ *  Copyright (C) 2007 Marvell International Ltd.
+ *
+ *  Derived from drivers/i2c/chips/pca9539.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; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
+
+#include <asm/gpio.h>
+
+#define PCA953X_INPUT          0
+#define PCA953X_OUTPUT         1
+#define PCA953X_INVERT         2
+#define PCA953X_DIRECTION      3
+
+/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */
+struct pca953x_desc {
+       char            name[I2C_NAME_SIZE];
+       unsigned long   driver_data;
+};
+
+static const struct pca953x_desc pca953x_descs[] = {
+       { "pca9534", 8, },
+       { "pca9535", 16, },
+       { "pca9536", 4, },
+       { "pca9537", 4, },
+       { "pca9538", 8, },
+       { "pca9539", 16, },
+       /* REVISIT several pca955x parts should work here too */
+};
+
+struct pca953x_chip {
+       unsigned gpio_start;
+       uint16_t reg_output;
+       uint16_t reg_direction;
+
+       struct i2c_client *client;
+       struct gpio_chip gpio_chip;
+};
+
+/* NOTE:  we can't currently rely on fault codes to come from SMBus
+ * calls, so we map all errors to EIO here and return zero otherwise.
+ */
+static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
+{
+       int ret;
+
+       if (chip->gpio_chip.ngpio <= 8)
+               ret = i2c_smbus_write_byte_data(chip->client, reg, val);
+       else
+               ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);
+
+       if (ret < 0) {
+               dev_err(&chip->client->dev, "failed writing register\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val)
+{
+       int ret;
+
+       if (chip->gpio_chip.ngpio <= 8)
+               ret = i2c_smbus_read_byte_data(chip->client, reg);
+       else
+               ret = i2c_smbus_read_word_data(chip->client, reg << 1);
+
+       if (ret < 0) {
+               dev_err(&chip->client->dev, "failed reading register\n");
+               return -EIO;
+       }
+
+       *val = (uint16_t)ret;
+       return 0;
+}
+
+static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+{
+       struct pca953x_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+       reg_val = chip->reg_direction | (1u << off);
+       ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+       if (ret)
+               return ret;
+
+       chip->reg_direction = reg_val;
+       return 0;
+}
+
+static int pca953x_gpio_direction_output(struct gpio_chip *gc,
+               unsigned off, int val)
+{
+       struct pca953x_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+       /* set output level */
+       if (val)
+               reg_val = chip->reg_output | (1u << off);
+       else
+               reg_val = chip->reg_output & ~(1u << off);
+
+       ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+       if (ret)
+               return ret;
+
+       chip->reg_output = reg_val;
+
+       /* then direction */
+       reg_val = chip->reg_direction & ~(1u << off);
+       ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+       if (ret)
+               return ret;
+
+       chip->reg_direction = reg_val;
+       return 0;
+}
+
+static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
+{
+       struct pca953x_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+       ret = pca953x_read_reg(chip, PCA953X_INPUT, &reg_val);
+       if (ret < 0) {
+               /* NOTE:  diagnostic already emitted; that's all we should
+                * do unless gpio_*_value_cansleep() calls become different
+                * from their nonsleeping siblings (and report faults).
+                */
+               return 0;
+       }
+
+       return (reg_val & (1u << off)) ? 1 : 0;
+}
+
+static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
+{
+       struct pca953x_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+       if (val)
+               reg_val = chip->reg_output | (1u << off);
+       else
+               reg_val = chip->reg_output & ~(1u << off);
+
+       ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+       if (ret)
+               return;
+
+       chip->reg_output = reg_val;
+}
+
+static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
+{
+       struct gpio_chip *gc;
+
+       gc = &chip->gpio_chip;
+
+       gc->direction_input  = pca953x_gpio_direction_input;
+       gc->direction_output = pca953x_gpio_direction_output;
+       gc->get = pca953x_gpio_get_value;
+       gc->set = pca953x_gpio_set_value;
+
+       gc->base = chip->gpio_start;
+       gc->ngpio = gpios;
+       gc->label = chip->client->name;
+}
+
+static int __devinit pca953x_probe(struct i2c_client *client)
+{
+       struct pca953x_platform_data *pdata;
+       struct pca953x_chip *chip;
+       int ret, i;
+       const struct pca953x_desc *id = NULL;
+
+       pdata = client->dev.platform_data;
+       if (pdata == NULL)
+               return -ENODEV;
+
+       /* this loop vanishes when we get i2c_device_id */
+       for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++)
+               if (!strcmp(pca953x_descs[i].name, client->name)) {
+                       id = pca953x_descs + i;
+                       break;
+               }
+       if (!id)
+               return -ENODEV;
+
+       chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       chip->client = client;
+
+       chip->gpio_start = pdata->gpio_base;
+
+       /* initialize cached registers from their original values.
+        * we can't share this chip with another i2c master.
+        */
+       pca953x_setup_gpio(chip, id->driver_data);
+
+       ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+       if (ret)
+               goto out_failed;
+
+       ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction);
+       if (ret)
+               goto out_failed;
+
+       /* set platform specific polarity inversion */
+       ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert);
+       if (ret)
+               goto out_failed;
+
+
+       ret = gpiochip_add(&chip->gpio_chip);
+       if (ret)
+               goto out_failed;
+
+       if (pdata->setup) {
+               ret = pdata->setup(client, chip->gpio_chip.base,
+                               chip->gpio_chip.ngpio, pdata->context);
+               if (ret < 0)
+                       dev_warn(&client->dev, "setup failed, %d\n", ret);
+       }
+
+       i2c_set_clientdata(client, chip);
+       return 0;
+
+out_failed:
+       kfree(chip);
+       return ret;
+}
+
+static int pca953x_remove(struct i2c_client *client)
+{
+       struct pca953x_platform_data *pdata = client->dev.platform_data;
+       struct pca953x_chip *chip = i2c_get_clientdata(client);
+       int ret = 0;
+
+       if (pdata->teardown) {
+               ret = pdata->teardown(client, chip->gpio_chip.base,
+                               chip->gpio_chip.ngpio, pdata->context);
+               if (ret < 0) {
+                       dev_err(&client->dev, "%s failed, %d\n",
+                                       "teardown", ret);
+                       return ret;
+               }
+       }
+
+       ret = gpiochip_remove(&chip->gpio_chip);
+       if (ret) {
+               dev_err(&client->dev, "%s failed, %d\n",
+                               "gpiochip_remove()", ret);
+               return ret;
+       }
+
+       kfree(chip);
+       return 0;
+}
+
+static struct i2c_driver pca953x_driver = {
+       .driver = {
+               .name   = "pca953x",
+       },
+       .probe          = pca953x_probe,
+       .remove         = pca953x_remove,
+};
+
+static int __init pca953x_init(void)
+{
+       return i2c_add_driver(&pca953x_driver);
+}
+module_init(pca953x_init);
+
+static void __exit pca953x_exit(void)
+{
+       i2c_del_driver(&pca953x_driver);
+}
+module_exit(pca953x_exit);
+
+MODULE_AUTHOR("eric miao <eric.miao@marvell.com>");
+MODULE_DESCRIPTION("GPIO expander driver for PCA953x");
+MODULE_LICENSE("GPL");
index fd0ef8268950138a304c54c640ca51807ad67bbc..6daea896c5dbe34ca18095e12f8f708e73a4c7b0 100644 (file)
@@ -1049,7 +1049,7 @@ static int init_irq (ide_hwif_t *hwif)
         */
        if (!match || match->irq != hwif->irq) {
                int sa = 0;
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
                sa = IRQF_SHARED;
 #endif /* __mc68000__ || CONFIG_APUS */
 
@@ -1072,7 +1072,7 @@ static int init_irq (ide_hwif_t *hwif)
                        hwif->rqsize = 65536;
        }
 
-#if !defined(__mc68000__) && !defined(CONFIG_APUS)
+#if !defined(__mc68000__)
        printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
                hwif->io_ports[IDE_DATA_OFFSET],
                hwif->io_ports[IDE_DATA_OFFSET]+7,
@@ -1080,7 +1080,7 @@ static int init_irq (ide_hwif_t *hwif)
 #else
        printk("%s at 0x%08lx on irq %d", hwif->name,
                hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
-#endif /* __mc68000__ && CONFIG_APUS */
+#endif /* __mc68000__ */
        if (match)
                printk(" (%sed with %s)",
                        hwif->sharing_irq ? "shar" : "serializ", match->name);
index 26c82ce602dedb7f3da016152b078428f64e899e..688fcae17488d85505d6a44cd6a2c36fa87e0c9a 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/ide.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
index 2ae6c6016a8665d79eb4f6dd63d76a3675230f30..28ae15ed12c57a81e5e92a1cda6e421efd3bb284 100644 (file)
@@ -109,7 +109,7 @@ struct h3600_dev {
 static irqreturn_t action_button_handler(int irq, void *dev_id)
 {
        int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
-       struct input_dev *dev = (struct input_dev *) dev_id;
+       struct input_dev *dev = dev_id;
 
        input_report_key(dev, KEY_ENTER, down);
        input_sync(dev);
@@ -120,7 +120,7 @@ static irqreturn_t action_button_handler(int irq, void *dev_id)
 static irqreturn_t npower_button_handler(int irq, void *dev_id)
 {
        int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
-       struct input_dev *dev = (struct input_dev *) dev_id;
+       struct input_dev *dev = dev_id;
 
        /*
         * This interrupt is only called when we release the key. So we have
index ee2b0b9f8f46b873822dc20db69f2625b9a8d650..8325022e2bed5951c04e67efc989aabec005bc6a 100644 (file)
@@ -310,7 +310,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        }
                        break;
                case ISDN_CMD_DIAL:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -339,7 +339,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        }
                        return ret;
                case ISDN_CMD_ACCEPTD:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -347,11 +347,11 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                                actcapi_select_b2_protocol_req(card, chan);
                        return 0;
                case ISDN_CMD_ACCEPTB:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        return 0;
                case ISDN_CMD_HANGUP:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -366,7 +366,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        }
                        return 0;
                case ISDN_CMD_SETEAZ:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -386,7 +386,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        actcapi_listen_req(card);
                        return 0;
                case ISDN_CMD_CLREAZ:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -394,14 +394,14 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        actcapi_listen_req(card);
                        return 0;
                case ISDN_CMD_SETL2:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
                        chan->l2prot = (c->arg >> 8);
                        return 0;
                case ISDN_CMD_SETL3:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
                                printk(KERN_WARNING "L3 protocol unknown\n");
@@ -524,7 +524,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel)
         act2000_card *card = act2000_findcard(id);
 
         if (card) {
-                if (!card->flags & ACT2000_FLAGS_RUNNING)
+                if (!(card->flags & ACT2000_FLAGS_RUNNING))
                         return -ENODEV;
                 return (len);
         }
@@ -539,7 +539,7 @@ if_readstatus(u_char __user * buf, int len, int id, int channel)
         act2000_card *card = act2000_findcard(id);
        
         if (card) {
-                if (!card->flags & ACT2000_FLAGS_RUNNING)
+                if (!(card->flags & ACT2000_FLAGS_RUNNING))
                         return -ENODEV;
                 return (act2000_readstatus(buf, len, card));
         }
@@ -554,7 +554,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
         act2000_card *card = act2000_findcard(id);
        
         if (card) {
-                if (!card->flags & ACT2000_FLAGS_RUNNING)
+                if (!(card->flags & ACT2000_FLAGS_RUNNING))
                         return -ENODEV;
                return (act2000_sendbuf(card, channel, ack, skb));
         }
index 00a3be5b862bbf87416231c2f91c58851e593c87..091deb9d1c47cfb85e5252effbf019d65aba67e3 100644 (file)
@@ -350,8 +350,8 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
        unsigned char *src, c;
        int procbytes;
 
-       head = atomic_read(&inbuf->head);
-       tail = atomic_read(&inbuf->tail);
+       head = inbuf->head;
+       tail = inbuf->tail;
        gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
 
        if (head != tail) {
@@ -361,7 +361,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
                gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
 
                while (numbytes) {
-                       if (atomic_read(&cs->mstate) == MS_LOCKED) {
+                       if (cs->mstate == MS_LOCKED) {
                                procbytes = lock_loop(src, numbytes, inbuf);
                                src += procbytes;
                                numbytes -= procbytes;
@@ -436,7 +436,7 @@ nextbyte:
                }
 
                gig_dbg(DEBUG_INTR, "setting head to %u", head);
-               atomic_set(&inbuf->head, head);
+               inbuf->head = head;
        }
 }
 EXPORT_SYMBOL_GPL(gigaset_m10x_input);
index af7648274b3801564a4314c1623b6fd117fe919f..5255b5e20e132021c46259eb0f44de8c3af3fb10 100644 (file)
@@ -73,6 +73,14 @@ static int gigaset_probe(struct usb_interface *interface,
 /* Function will be called if the device is unplugged */
 static void gigaset_disconnect(struct usb_interface *interface);
 
+/* functions called before/after suspend */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
+static int gigaset_resume(struct usb_interface *intf);
+
+/* functions called before/after device reset */
+static int gigaset_pre_reset(struct usb_interface *intf);
+static int gigaset_post_reset(struct usb_interface *intf);
+
 static int atread_submit(struct cardstate *, int);
 static void stopurbs(struct bas_bc_state *);
 static int req_submit(struct bc_state *, int, int, int);
@@ -105,8 +113,9 @@ struct bas_cardstate {
        unsigned char           int_in_buf[3];
 
        spinlock_t              lock;           /* locks all following */
-       atomic_t                basstate;       /* bitmap (BS_*) */
+       int                     basstate;       /* bitmap (BS_*) */
        int                     pending;        /* uncompleted base request */
+       wait_queue_head_t       waitqueue;
        int                     rcvbuf_size;    /* size of AT receive buffer */
                                                /* 0: no receive in progress */
        int                     retry_cmd_in;   /* receive req retry count */
@@ -121,10 +130,10 @@ struct bas_cardstate {
 #define BS_ATTIMER     0x020   /* waiting for HD_READY_SEND_ATDATA */
 #define BS_ATRDPEND    0x040   /* urb_cmd_in in use */
 #define BS_ATWRPEND    0x080   /* urb_cmd_out in use */
+#define BS_SUSPEND     0x100   /* USB port suspended */
 
 
 static struct gigaset_driver *driver = NULL;
-static struct cardstate *cardstate = NULL;
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver gigaset_usb_driver = {
@@ -132,6 +141,11 @@ static struct usb_driver gigaset_usb_driver = {
        .probe =        gigaset_probe,
        .disconnect =   gigaset_disconnect,
        .id_table =     gigaset_table,
+       .suspend =      gigaset_suspend,
+       .resume =       gigaset_resume,
+       .reset_resume = gigaset_post_reset,
+       .pre_reset =    gigaset_pre_reset,
+       .post_reset =   gigaset_post_reset,
 };
 
 /* get message text for usb_submit_urb return code
@@ -248,12 +262,12 @@ static inline void dump_urb(enum debuglevel level, const char *tag,
        if (urb) {
                gig_dbg(level,
                        "  dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, "
-                       "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,",
+                       "hcpriv=0x%08lx, transfer_flags=0x%x,",
                        (unsigned long) urb->dev,
                        usb_pipetype_str(urb->pipe),
                        usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe),
                        usb_pipein(urb->pipe) ? "in" : "out",
-                       urb->status, (unsigned long) urb->hcpriv,
+                       (unsigned long) urb->hcpriv,
                        urb->transfer_flags);
                gig_dbg(level,
                        "  transfer_buffer=0x%08lx[%d], actual_length=%d, "
@@ -355,27 +369,27 @@ static void check_pending(struct bas_cardstate *ucs)
        case 0:
                break;
        case HD_OPEN_ATCHANNEL:
-               if (atomic_read(&ucs->basstate) & BS_ATOPEN)
+               if (ucs->basstate & BS_ATOPEN)
                        ucs->pending = 0;
                break;
        case HD_OPEN_B1CHANNEL:
-               if (atomic_read(&ucs->basstate) & BS_B1OPEN)
+               if (ucs->basstate & BS_B1OPEN)
                        ucs->pending = 0;
                break;
        case HD_OPEN_B2CHANNEL:
-               if (atomic_read(&ucs->basstate) & BS_B2OPEN)
+               if (ucs->basstate & BS_B2OPEN)
                        ucs->pending = 0;
                break;
        case HD_CLOSE_ATCHANNEL:
-               if (!(atomic_read(&ucs->basstate) & BS_ATOPEN))
+               if (!(ucs->basstate & BS_ATOPEN))
                        ucs->pending = 0;
                break;
        case HD_CLOSE_B1CHANNEL:
-               if (!(atomic_read(&ucs->basstate) & BS_B1OPEN))
+               if (!(ucs->basstate & BS_B1OPEN))
                        ucs->pending = 0;
                break;
        case HD_CLOSE_B2CHANNEL:
-               if (!(atomic_read(&ucs->basstate) & BS_B2OPEN))
+               if (!(ucs->basstate & BS_B2OPEN))
                        ucs->pending = 0;
                break;
        case HD_DEVICE_INIT_ACK:                /* no reply expected */
@@ -441,8 +455,8 @@ inline static int update_basstate(struct bas_cardstate *ucs,
        int state;
 
        spin_lock_irqsave(&ucs->lock, flags);
-       state = atomic_read(&ucs->basstate);
-       atomic_set(&ucs->basstate, (state & ~clear) | set);
+       state = ucs->basstate;
+       ucs->basstate = (state & ~clear) | set;
        spin_unlock_irqrestore(&ucs->lock, flags);
        return state;
 }
@@ -459,11 +473,13 @@ static void read_ctrl_callback(struct urb *urb)
        struct inbuf_t *inbuf = urb->context;
        struct cardstate *cs = inbuf->cs;
        struct bas_cardstate *ucs = cs->hw.bas;
+       int status = urb->status;
        int have_data = 0;
        unsigned numbytes;
        int rc;
 
        update_basstate(ucs, 0, BS_ATRDPEND);
+       wake_up(&ucs->waitqueue);
 
        if (!ucs->rcvbuf_size) {
                dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
@@ -472,7 +488,7 @@ static void read_ctrl_callback(struct urb *urb)
 
        del_timer(&ucs->timer_cmd_in);
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                         /* normal completion */
                numbytes = urb->actual_length;
                if (unlikely(numbytes != ucs->rcvbuf_size)) {
@@ -506,12 +522,12 @@ static void read_ctrl_callback(struct urb *urb)
        case -ESHUTDOWN:                /* device shut down */
                /* no action necessary */
                gig_dbg(DEBUG_USBREQ, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                break;
 
        default:                        /* severe trouble */
                dev_warn(cs->dev, "control read: %s\n",
-                        get_usb_statmsg(urb->status));
+                        get_usb_statmsg(status));
                if (ucs->retry_cmd_in++ < BAS_RETRY) {
                        dev_notice(cs->dev, "control read: retry %d\n",
                                   ucs->retry_cmd_in);
@@ -550,17 +566,28 @@ static void read_ctrl_callback(struct urb *urb)
 static int atread_submit(struct cardstate *cs, int timeout)
 {
        struct bas_cardstate *ucs = cs->hw.bas;
+       int basstate;
        int ret;
 
        gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)",
                ucs->rcvbuf_size);
 
-       if (update_basstate(ucs, BS_ATRDPEND, 0) & BS_ATRDPEND) {
+       basstate = update_basstate(ucs, BS_ATRDPEND, 0);
+       if (basstate & BS_ATRDPEND) {
                dev_err(cs->dev,
                        "could not submit HD_READ_ATMESSAGE: URB busy\n");
                return -EBUSY;
        }
 
+       if (basstate & BS_SUSPEND) {
+               dev_notice(cs->dev,
+                          "HD_READ_ATMESSAGE not submitted, "
+                          "suspend in progress\n");
+               update_basstate(ucs, 0, BS_ATRDPEND);
+               /* treat like disconnect */
+               return -ENODEV;
+       }
+
        ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ;
        ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE;
        ucs->dr_cmd_in.wValue = 0;
@@ -601,12 +628,13 @@ static void read_int_callback(struct urb *urb)
        struct cardstate *cs = urb->context;
        struct bas_cardstate *ucs = cs->hw.bas;
        struct bc_state *bcs;
+       int status = urb->status;
        unsigned long flags;
        int rc;
        unsigned l;
        int channel;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                 /* success */
                break;
        case -ENOENT:                   /* cancelled */
@@ -614,7 +642,7 @@ static void read_int_callback(struct urb *urb)
        case -EINPROGRESS:              /* pending */
                /* ignore silently */
                gig_dbg(DEBUG_USBREQ, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                return;
        case -ENODEV:                   /* device removed */
        case -ESHUTDOWN:                /* device shut down */
@@ -623,7 +651,7 @@ static void read_int_callback(struct urb *urb)
                return;
        default:                /* severe trouble */
                dev_warn(cs->dev, "interrupt read: %s\n",
-                        get_usb_statmsg(urb->status));
+                        get_usb_statmsg(status));
                //FIXME corrective action? resubmission always ok?
                goto resubmit;
        }
@@ -745,6 +773,7 @@ static void read_int_callback(struct urb *urb)
        }
 
        check_pending(ucs);
+       wake_up(&ucs->waitqueue);
 
 resubmit:
        rc = usb_submit_urb(urb, GFP_ATOMIC);
@@ -766,17 +795,18 @@ static void read_iso_callback(struct urb *urb)
 {
        struct bc_state *bcs;
        struct bas_bc_state *ubc;
+       int status = urb->status;
        unsigned long flags;
        int i, rc;
 
        /* status codes not worth bothering the tasklet with */
-       if (unlikely(urb->status == -ENOENT ||
-                    urb->status == -ECONNRESET ||
-                    urb->status == -EINPROGRESS ||
-                    urb->status == -ENODEV ||
-                    urb->status == -ESHUTDOWN)) {
+       if (unlikely(status == -ENOENT ||
+                    status == -ECONNRESET ||
+                    status == -EINPROGRESS ||
+                    status == -ENODEV ||
+                    status == -ESHUTDOWN)) {
                gig_dbg(DEBUG_ISO, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                return;
        }
 
@@ -787,10 +817,11 @@ static void read_iso_callback(struct urb *urb)
        if (likely(ubc->isoindone == NULL)) {
                /* pass URB to tasklet */
                ubc->isoindone = urb;
+               ubc->isoinstatus = status;
                tasklet_schedule(&ubc->rcvd_tasklet);
        } else {
                /* tasklet still busy, drop data and resubmit URB */
-               ubc->loststatus = urb->status;
+               ubc->loststatus = status;
                for (i = 0; i < BAS_NUMFRAMES; i++) {
                        ubc->isoinlost += urb->iso_frame_desc[i].actual_length;
                        if (unlikely(urb->iso_frame_desc[i].status != 0 &&
@@ -800,7 +831,7 @@ static void read_iso_callback(struct urb *urb)
                        urb->iso_frame_desc[i].status = 0;
                        urb->iso_frame_desc[i].actual_length = 0;
                }
-               if (likely(atomic_read(&ubc->running))) {
+               if (likely(ubc->running)) {
                        /* urb->dev is clobbered by USB subsystem */
                        urb->dev = bcs->cs->hw.bas->udev;
                        urb->transfer_flags = URB_ISO_ASAP;
@@ -831,22 +862,24 @@ static void write_iso_callback(struct urb *urb)
 {
        struct isow_urbctx_t *ucx;
        struct bas_bc_state *ubc;
+       int status = urb->status;
        unsigned long flags;
 
        /* status codes not worth bothering the tasklet with */
-       if (unlikely(urb->status == -ENOENT ||
-                    urb->status == -ECONNRESET ||
-                    urb->status == -EINPROGRESS ||
-                    urb->status == -ENODEV ||
-                    urb->status == -ESHUTDOWN)) {
+       if (unlikely(status == -ENOENT ||
+                    status == -ECONNRESET ||
+                    status == -EINPROGRESS ||
+                    status == -ENODEV ||
+                    status == -ESHUTDOWN)) {
                gig_dbg(DEBUG_ISO, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                return;
        }
 
        /* pass URB context to tasklet */
        ucx = urb->context;
        ubc = ucx->bcs->hw.bas;
+       ucx->status = status;
 
        spin_lock_irqsave(&ubc->isooutlock, flags);
        ubc->isooutovfl = ubc->isooutdone;
@@ -875,7 +908,7 @@ static int starturbs(struct bc_state *bcs)
                bcs->inputstate |= INS_flag_hunt;
 
        /* submit all isochronous input URBs */
-       atomic_set(&ubc->running, 1);
+       ubc->running = 1;
        for (k = 0; k < BAS_INURBS; k++) {
                urb = ubc->isoinurbs[k];
                if (!urb) {
@@ -932,15 +965,15 @@ static int starturbs(struct bc_state *bcs)
                ubc->isoouturbs[k].limit = -1;
        }
 
-       /* submit two URBs, keep third one */
-       for (k = 0; k < 2; ++k) {
+       /* keep one URB free, submit the others */
+       for (k = 0; k < BAS_OUTURBS-1; ++k) {
                dump_urb(DEBUG_ISO, "Initial isoc write", urb);
                rc = usb_submit_urb(ubc->isoouturbs[k].urb, GFP_ATOMIC);
                if (rc != 0)
                        goto error;
        }
        dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb);
-       ubc->isooutfree = &ubc->isoouturbs[2];
+       ubc->isooutfree = &ubc->isoouturbs[BAS_OUTURBS-1];
        ubc->isooutdone = ubc->isooutovfl = NULL;
        return 0;
  error:
@@ -958,7 +991,7 @@ static void stopurbs(struct bas_bc_state *ubc)
 {
        int k, rc;
 
-       atomic_set(&ubc->running, 0);
+       ubc->running = 0;
 
        for (k = 0; k < BAS_INURBS; ++k) {
                rc = usb_unlink_urb(ubc->isoinurbs[k]);
@@ -1034,7 +1067,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
                        }
                        break;
                }
-               ucx->limit = atomic_read(&ubc->isooutbuf->nextread);
+               ucx->limit = ubc->isooutbuf->nextread;
                ifd->status = 0;
                ifd->actual_length = 0;
        }
@@ -1070,6 +1103,7 @@ static void write_iso_tasklet(unsigned long data)
        struct cardstate *cs = bcs->cs;
        struct isow_urbctx_t *done, *next, *ovfl;
        struct urb *urb;
+       int status;
        struct usb_iso_packet_descriptor *ifd;
        int offset;
        unsigned long flags;
@@ -1080,7 +1114,7 @@ static void write_iso_tasklet(unsigned long data)
 
        /* loop while completed URBs arrive in time */
        for (;;) {
-               if (unlikely(!(atomic_read(&ubc->running)))) {
+               if (unlikely(!(ubc->running))) {
                        gig_dbg(DEBUG_ISO, "%s: not running", __func__);
                        return;
                }
@@ -1126,7 +1160,8 @@ static void write_iso_tasklet(unsigned long data)
 
                /* process completed URB */
                urb = done->urb;
-               switch (urb->status) {
+               status = done->status;
+               switch (status) {
                case -EXDEV:                    /* partial completion */
                        gig_dbg(DEBUG_ISO, "%s: URB partially completed",
                                __func__);
@@ -1179,12 +1214,12 @@ static void write_iso_tasklet(unsigned long data)
                        break;
                default:                        /* severe trouble */
                        dev_warn(cs->dev, "isochronous write: %s\n",
-                                get_usb_statmsg(urb->status));
+                                get_usb_statmsg(status));
                }
 
                /* mark the write buffer area covered by this URB as free */
                if (done->limit >= 0)
-                       atomic_set(&ubc->isooutbuf->read, done->limit);
+                       ubc->isooutbuf->read = done->limit;
 
                /* mark URB as free */
                spin_lock_irqsave(&ubc->isooutlock, flags);
@@ -1233,6 +1268,7 @@ static void read_iso_tasklet(unsigned long data)
        struct bas_bc_state *ubc = bcs->hw.bas;
        struct cardstate *cs = bcs->cs;
        struct urb *urb;
+       int status;
        char *rcvbuf;
        unsigned long flags;
        int totleft, numbytes, offset, frame, rc;
@@ -1245,6 +1281,7 @@ static void read_iso_tasklet(unsigned long data)
                        spin_unlock_irqrestore(&ubc->isoinlock, flags);
                        return;
                }
+               status = ubc->isoinstatus;
                ubc->isoindone = NULL;
                if (unlikely(ubc->loststatus != -EINPROGRESS)) {
                        dev_warn(cs->dev,
@@ -1256,15 +1293,15 @@ static void read_iso_tasklet(unsigned long data)
                }
                spin_unlock_irqrestore(&ubc->isoinlock, flags);
 
-               if (unlikely(!(atomic_read(&ubc->running)))) {
+               if (unlikely(!(ubc->running))) {
                        gig_dbg(DEBUG_ISO,
                                "%s: channel not running, "
                                "dropped URB with status: %s",
-                               __func__, get_usb_statmsg(urb->status));
+                               __func__, get_usb_statmsg(status));
                        return;
                }
 
-               switch (urb->status) {
+               switch (status) {
                case 0:                         /* normal completion */
                        break;
                case -EXDEV:                    /* inspect individual frames
@@ -1276,7 +1313,7 @@ static void read_iso_tasklet(unsigned long data)
                case -ECONNRESET:
                case -EINPROGRESS:
                        gig_dbg(DEBUG_ISO, "%s: %s",
-                               __func__, get_usb_statmsg(urb->status));
+                               __func__, get_usb_statmsg(status));
                        continue;               /* -> skip */
                case -EPIPE:
                        dev_err(cs->dev, "isochronous read stalled\n");
@@ -1284,7 +1321,7 @@ static void read_iso_tasklet(unsigned long data)
                        continue;               /* -> skip */
                default:                        /* severe trouble */
                        dev_warn(cs->dev, "isochronous read: %s\n",
-                                get_usb_statmsg(urb->status));
+                                get_usb_statmsg(status));
                        goto error;
                }
 
@@ -1406,6 +1443,8 @@ static void req_timeout(unsigned long data)
                dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n",
                         pending);
        }
+
+       wake_up(&ucs->waitqueue);
 }
 
 /* write_ctrl_callback
@@ -1418,11 +1457,12 @@ static void req_timeout(unsigned long data)
 static void write_ctrl_callback(struct urb *urb)
 {
        struct bas_cardstate *ucs = urb->context;
+       int status = urb->status;
        int rc;
        unsigned long flags;
 
        /* check status */
-       switch (urb->status) {
+       switch (status) {
        case 0:                                 /* normal completion */
                spin_lock_irqsave(&ucs->lock, flags);
                switch (ucs->pending) {
@@ -1441,20 +1481,22 @@ static void write_ctrl_callback(struct urb *urb)
        case -ESHUTDOWN:                /* device shut down */
                /* ignore silently */
                gig_dbg(DEBUG_USBREQ, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                break;
 
        default:                                /* any failure */
-               if (++ucs->retry_ctrl > BAS_RETRY) {
+               /* don't retry if suspend requested */
+               if (++ucs->retry_ctrl > BAS_RETRY ||
+                   (ucs->basstate & BS_SUSPEND)) {
                        dev_err(&ucs->interface->dev,
                                "control request 0x%02x failed: %s\n",
                                ucs->dr_ctrl.bRequest,
-                               get_usb_statmsg(urb->status));
+                               get_usb_statmsg(status));
                        break;          /* give up */
                }
                dev_notice(&ucs->interface->dev,
                           "control request 0x%02x: %s, retry %d\n",
-                          ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status),
+                          ucs->dr_ctrl.bRequest, get_usb_statmsg(status),
                           ucs->retry_ctrl);
                /* urb->dev is clobbered by USB subsystem */
                urb->dev = ucs->udev;
@@ -1474,6 +1516,7 @@ static void write_ctrl_callback(struct urb *urb)
        del_timer(&ucs->timer_ctrl);
        ucs->pending = 0;
        spin_unlock_irqrestore(&ucs->lock, flags);
+       wake_up(&ucs->waitqueue);
 }
 
 /* req_submit
@@ -1548,37 +1591,46 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
  */
 static int gigaset_init_bchannel(struct bc_state *bcs)
 {
+       struct cardstate *cs = bcs->cs;
        int req, ret;
        unsigned long flags;
 
-       spin_lock_irqsave(&bcs->cs->lock, flags);
-       if (unlikely(!bcs->cs->connected)) {
+       spin_lock_irqsave(&cs->lock, flags);
+       if (unlikely(!cs->connected)) {
                gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
-               spin_unlock_irqrestore(&bcs->cs->lock, flags);
+               spin_unlock_irqrestore(&cs->lock, flags);
                return -ENODEV;
        }
 
+       if (cs->hw.bas->basstate & BS_SUSPEND) {
+               dev_notice(cs->dev,
+                          "not starting isochronous I/O, "
+                          "suspend in progress\n");
+               spin_unlock_irqrestore(&cs->lock, flags);
+               return -EHOSTUNREACH;
+       }
+
        if ((ret = starturbs(bcs)) < 0) {
-               dev_err(bcs->cs->dev,
+               dev_err(cs->dev,
                        "could not start isochronous I/O for channel B%d: %s\n",
                        bcs->channel + 1,
                        ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret));
                if (ret != -ENODEV)
                        error_hangup(bcs);
-               spin_unlock_irqrestore(&bcs->cs->lock, flags);
+               spin_unlock_irqrestore(&cs->lock, flags);
                return ret;
        }
 
        req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL;
        if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) {
-               dev_err(bcs->cs->dev, "could not open channel B%d\n",
+               dev_err(cs->dev, "could not open channel B%d\n",
                        bcs->channel + 1);
                stopurbs(bcs->hw.bas);
                if (ret != -ENODEV)
                        error_hangup(bcs);
        }
 
-       spin_unlock_irqrestore(&bcs->cs->lock, flags);
+       spin_unlock_irqrestore(&cs->lock, flags);
        return ret;
 }
 
@@ -1594,20 +1646,20 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
  */
 static int gigaset_close_bchannel(struct bc_state *bcs)
 {
+       struct cardstate *cs = bcs->cs;
        int req, ret;
        unsigned long flags;
 
-       spin_lock_irqsave(&bcs->cs->lock, flags);
-       if (unlikely(!bcs->cs->connected)) {
-               spin_unlock_irqrestore(&bcs->cs->lock, flags);
+       spin_lock_irqsave(&cs->lock, flags);
+       if (unlikely(!cs->connected)) {
+               spin_unlock_irqrestore(&cs->lock, flags);
                gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
                return -ENODEV;
        }
 
-       if (!(atomic_read(&bcs->cs->hw.bas->basstate) &
-             (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
+       if (!(cs->hw.bas->basstate & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
                /* channel not running: just signal common.c */
-               spin_unlock_irqrestore(&bcs->cs->lock, flags);
+               spin_unlock_irqrestore(&cs->lock, flags);
                gigaset_bchannel_down(bcs);
                return 0;
        }
@@ -1615,10 +1667,10 @@ static int gigaset_close_bchannel(struct bc_state *bcs)
        /* channel running: tell device to close it */
        req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL;
        if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0)
-               dev_err(bcs->cs->dev, "closing channel B%d failed\n",
+               dev_err(cs->dev, "closing channel B%d failed\n",
                        bcs->channel + 1);
 
-       spin_unlock_irqrestore(&bcs->cs->lock, flags);
+       spin_unlock_irqrestore(&cs->lock, flags);
        return ret;
 }
 
@@ -1665,12 +1717,14 @@ static void write_command_callback(struct urb *urb)
 {
        struct cardstate *cs = urb->context;
        struct bas_cardstate *ucs = cs->hw.bas;
+       int status = urb->status;
        unsigned long flags;
 
        update_basstate(ucs, 0, BS_ATWRPEND);
+       wake_up(&ucs->waitqueue);
 
        /* check status */
-       switch (urb->status) {
+       switch (status) {
        case 0:                                 /* normal completion */
                break;
        case -ENOENT:                   /* cancelled */
@@ -1680,26 +1734,33 @@ static void write_command_callback(struct urb *urb)
        case -ESHUTDOWN:                /* device shut down */
                /* ignore silently */
                gig_dbg(DEBUG_USBREQ, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                return;
        default:                                /* any failure */
                if (++ucs->retry_cmd_out > BAS_RETRY) {
                        dev_warn(cs->dev,
                                 "command write: %s, "
                                 "giving up after %d retries\n",
-                                get_usb_statmsg(urb->status),
+                                get_usb_statmsg(status),
                                 ucs->retry_cmd_out);
                        break;
                }
+               if (ucs->basstate & BS_SUSPEND) {
+                       dev_warn(cs->dev,
+                                "command write: %s, "
+                                "won't retry - suspend requested\n",
+                                get_usb_statmsg(status));
+                       break;
+               }
                if (cs->cmdbuf == NULL) {
                        dev_warn(cs->dev,
                                 "command write: %s, "
                                 "cannot retry - cmdbuf gone\n",
-                                get_usb_statmsg(urb->status));
+                                get_usb_statmsg(status));
                        break;
                }
                dev_notice(cs->dev, "command write: %s, retry %d\n",
-                          get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+                          get_usb_statmsg(status), ucs->retry_cmd_out);
                if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0)
                        /* resubmitted - bypass regular exit block */
                        return;
@@ -1799,8 +1860,14 @@ static int start_cbsend(struct cardstate *cs)
        int rc;
        int retval = 0;
 
+       /* check if suspend requested */
+       if (ucs->basstate & BS_SUSPEND) {
+               gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "suspending");
+               return -EHOSTUNREACH;
+       }
+
        /* check if AT channel is open */
-       if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) {
+       if (!(ucs->basstate & BS_ATOPEN)) {
                gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open");
                rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT);
                if (rc < 0) {
@@ -1816,8 +1883,7 @@ static int start_cbsend(struct cardstate *cs)
        /* try to send first command in queue */
        spin_lock_irqsave(&cs->cmdlock, flags);
 
-       while ((cb = cs->cmdbuf) != NULL &&
-              atomic_read(&ucs->basstate) & BS_ATREADY) {
+       while ((cb = cs->cmdbuf) != NULL && (ucs->basstate & BS_ATREADY)) {
                ucs->retry_cmd_out = 0;
                rc = atwrite_submit(cs, cb->buf, cb->len);
                if (unlikely(rc)) {
@@ -1855,7 +1921,7 @@ static int gigaset_write_cmd(struct cardstate *cs,
        unsigned long flags;
        int rc;
 
-       gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+       gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
                           "CMD Transmit", len, buf);
 
@@ -1970,7 +2036,7 @@ static int gigaset_freebcshw(struct bc_state *bcs)
                return 0;
 
        /* kill URBs and tasklets before freeing - better safe than sorry */
-       atomic_set(&ubc->running, 0);
+       ubc->running = 0;
        gig_dbg(DEBUG_INIT, "%s: killing iso URBs", __func__);
        for (i = 0; i < BAS_OUTURBS; ++i) {
                usb_kill_urb(ubc->isoouturbs[i].urb);
@@ -2005,7 +2071,7 @@ static int gigaset_initbcshw(struct bc_state *bcs)
                return 0;
        }
 
-       atomic_set(&ubc->running, 0);
+       ubc->running = 0;
        atomic_set(&ubc->corrbytes, 0);
        spin_lock_init(&ubc->isooutlock);
        for (i = 0; i < BAS_OUTURBS; ++i) {
@@ -2050,7 +2116,7 @@ static void gigaset_reinitbcshw(struct bc_state *bcs)
 {
        struct bas_bc_state *ubc = bcs->hw.bas;
 
-       atomic_set(&bcs->hw.bas->running, 0);
+       bcs->hw.bas->running = 0;
        atomic_set(&bcs->hw.bas->corrbytes, 0);
        bcs->hw.bas->numsub = 0;
        spin_lock_init(&ubc->isooutlock);
@@ -2081,10 +2147,11 @@ static int gigaset_initcshw(struct cardstate *cs)
        spin_lock_init(&ucs->lock);
        ucs->pending = 0;
 
-       atomic_set(&ucs->basstate, 0);
+       ucs->basstate = 0;
        init_timer(&ucs->timer_ctrl);
        init_timer(&ucs->timer_atrdy);
        init_timer(&ucs->timer_cmd_in);
+       init_waitqueue_head(&ucs->waitqueue);
 
        return 1;
 }
@@ -2102,7 +2169,7 @@ static void freeurbs(struct cardstate *cs)
        int i, j;
 
        gig_dbg(DEBUG_INIT, "%s: killing URBs", __func__);
-       for (j = 0; j < 2; ++j) {
+       for (j = 0; j < BAS_CHANNELS; ++j) {
                ubc = cs->bcs[j].hw.bas;
                for (i = 0; i < BAS_OUTURBS; ++i) {
                        usb_kill_urb(ubc->isoouturbs[i].urb);
@@ -2179,11 +2246,11 @@ static int gigaset_probe(struct usb_interface *interface,
                 __func__, le16_to_cpu(udev->descriptor.idVendor),
                 le16_to_cpu(udev->descriptor.idProduct));
 
-       cs = gigaset_getunassignedcs(driver);
-       if (!cs) {
-               dev_err(&udev->dev, "no free cardstate\n");
+       /* allocate memory for our device state and intialize it */
+       cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode,
+                           GIGASET_MODULENAME);
+       if (!cs)
                return -ENODEV;
-       }
        ucs = cs->hw.bas;
 
        /* save off device structure ptrs for later use */
@@ -2203,7 +2270,7 @@ static int gigaset_probe(struct usb_interface *interface,
            !(ucs->urb_ctrl = usb_alloc_urb(0, GFP_KERNEL)))
                goto allocerr;
 
-       for (j = 0; j < 2; ++j) {
+       for (j = 0; j < BAS_CHANNELS; ++j) {
                ubc = cs->bcs[j].hw.bas;
                for (i = 0; i < BAS_OUTURBS; ++i)
                        if (!(ubc->isoouturbs[i].urb =
@@ -2237,7 +2304,7 @@ static int gigaset_probe(struct usb_interface *interface,
 
        /* tell common part that the device is ready */
        if (startmode == SM_LOCKED)
-               atomic_set(&cs->mstate, MS_LOCKED);
+               cs->mstate = MS_LOCKED;
 
        /* save address of controller structure */
        usb_set_intfdata(interface, cs);
@@ -2252,7 +2319,7 @@ allocerr:
 error:
        freeurbs(cs);
        usb_set_intfdata(interface, NULL);
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
        return -ENODEV;
 }
 
@@ -2272,11 +2339,10 @@ static void gigaset_disconnect(struct usb_interface *interface)
        dev_info(cs->dev, "disconnecting Gigaset base\n");
 
        /* mark base as not ready, all channels disconnected */
-       atomic_set(&ucs->basstate, 0);
+       ucs->basstate = 0;
 
        /* tell LL all channels are down */
-       //FIXME shouldn't gigaset_stop() do this?
-       for (j = 0; j < 2; ++j)
+       for (j = 0; j < BAS_CHANNELS; ++j)
                gigaset_bchannel_down(cs->bcs + j);
 
        /* stop driver (common part) */
@@ -2295,9 +2361,113 @@ static void gigaset_disconnect(struct usb_interface *interface)
        ucs->interface = NULL;
        ucs->udev = NULL;
        cs->dev = NULL;
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
 }
 
+/* gigaset_suspend
+ * This function is called before the USB connection is suspended.
+ */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+       struct bas_cardstate *ucs = cs->hw.bas;
+       int rc;
+
+       /* set suspend flag; this stops AT command/response traffic */
+       if (update_basstate(ucs, BS_SUSPEND, 0) & BS_SUSPEND) {
+               gig_dbg(DEBUG_SUSPEND, "already suspended");
+               return 0;
+       }
+
+       /* wait a bit for blocking conditions to go away */
+       rc = wait_event_timeout(ucs->waitqueue,
+                       !(ucs->basstate &
+                         (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)),
+                       BAS_TIMEOUT*HZ/10);
+       gig_dbg(DEBUG_SUSPEND, "wait_event_timeout() -> %d", rc);
+
+       /* check for conditions preventing suspend */
+       if (ucs->basstate & (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)) {
+               dev_warn(cs->dev, "cannot suspend:\n");
+               if (ucs->basstate & BS_B1OPEN)
+                       dev_warn(cs->dev, " B channel 1 open\n");
+               if (ucs->basstate & BS_B2OPEN)
+                       dev_warn(cs->dev, " B channel 2 open\n");
+               if (ucs->basstate & BS_ATRDPEND)
+                       dev_warn(cs->dev, " receiving AT reply\n");
+               if (ucs->basstate & BS_ATWRPEND)
+                       dev_warn(cs->dev, " sending AT command\n");
+               update_basstate(ucs, 0, BS_SUSPEND);
+               return -EBUSY;
+       }
+
+       /* close AT channel if open */
+       if (ucs->basstate & BS_ATOPEN) {
+               gig_dbg(DEBUG_SUSPEND, "closing AT channel");
+               rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, 0);
+               if (rc) {
+                       update_basstate(ucs, 0, BS_SUSPEND);
+                       return rc;
+               }
+               wait_event_timeout(ucs->waitqueue, !ucs->pending,
+                                  BAS_TIMEOUT*HZ/10);
+               /* in case of timeout, proceed anyway */
+       }
+
+       /* kill all URBs and timers that might still be pending */
+       usb_kill_urb(ucs->urb_ctrl);
+       usb_kill_urb(ucs->urb_int_in);
+       del_timer_sync(&ucs->timer_ctrl);
+
+       gig_dbg(DEBUG_SUSPEND, "suspend complete");
+       return 0;
+}
+
+/* gigaset_resume
+ * This function is called after the USB connection has been resumed.
+ */
+static int gigaset_resume(struct usb_interface *intf)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+       struct bas_cardstate *ucs = cs->hw.bas;
+       int rc;
+
+       /* resubmit interrupt URB for spontaneous messages from base */
+       rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL);
+       if (rc) {
+               dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
+                       get_usb_rcmsg(rc));
+               return rc;
+       }
+
+       /* clear suspend flag to reallow activity */
+       update_basstate(ucs, 0, BS_SUSPEND);
+
+       gig_dbg(DEBUG_SUSPEND, "resume complete");
+       return 0;
+}
+
+/* gigaset_pre_reset
+ * This function is called before the USB connection is reset.
+ */
+static int gigaset_pre_reset(struct usb_interface *intf)
+{
+       /* handle just like suspend */
+       return gigaset_suspend(intf, PMSG_ON);
+}
+
+/* gigaset_post_reset
+ * This function is called after the USB connection has been reset.
+ */
+static int gigaset_post_reset(struct usb_interface *intf)
+{
+       /* FIXME: send HD_DEVICE_INIT_ACK? */
+
+       /* resume operations */
+       return gigaset_resume(intf);
+}
+
+
 static const struct gigaset_ops gigops = {
        gigaset_write_cmd,
        gigaset_write_room,
@@ -2330,12 +2500,6 @@ static int __init bas_gigaset_init(void)
                                       &gigops, THIS_MODULE)) == NULL)
                goto error;
 
-       /* allocate memory for our device state and intialize it */
-       cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode,
-                                  GIGASET_MODULENAME);
-       if (!cardstate)
-               goto error;
-
        /* register this driver with the USB subsystem */
        result = usb_register(&gigaset_usb_driver);
        if (result < 0) {
@@ -2347,9 +2511,7 @@ static int __init bas_gigaset_init(void)
        info(DRIVER_DESC);
        return 0;
 
-error: if (cardstate)
-               gigaset_freecs(cardstate);
-       cardstate = NULL;
+error:
        if (driver)
                gigaset_freedriver(driver);
        driver = NULL;
@@ -2361,43 +2523,50 @@ error:  if (cardstate)
  */
 static void __exit bas_gigaset_exit(void)
 {
-       struct bas_cardstate *ucs = cardstate->hw.bas;
+       struct bas_cardstate *ucs;
+       int i;
 
        gigaset_blockdriver(driver); /* => probe will fail
                                      * => no gigaset_start any more
                                      */
 
-       gigaset_shutdown(cardstate);
-       /* from now on, no isdn callback should be possible */
-
-       /* close all still open channels */
-       if (atomic_read(&ucs->basstate) & BS_B1OPEN) {
-               gig_dbg(DEBUG_INIT, "closing B1 channel");
-               usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
-                               HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0,
-                               NULL, 0, BAS_TIMEOUT);
-       }
-       if (atomic_read(&ucs->basstate) & BS_B2OPEN) {
-               gig_dbg(DEBUG_INIT, "closing B2 channel");
-               usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
-                               HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0,
-                               NULL, 0, BAS_TIMEOUT);
-       }
-       if (atomic_read(&ucs->basstate) & BS_ATOPEN) {
-               gig_dbg(DEBUG_INIT, "closing AT channel");
-               usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
-                               HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0,
-                               NULL, 0, BAS_TIMEOUT);
+       /* stop all connected devices */
+       for (i = 0; i < driver->minors; i++) {
+               if (gigaset_shutdown(driver->cs + i) < 0)
+                       continue;               /* no device */
+               /* from now on, no isdn callback should be possible */
+
+               /* close all still open channels */
+               ucs = driver->cs[i].hw.bas;
+               if (ucs->basstate & BS_B1OPEN) {
+                       gig_dbg(DEBUG_INIT, "closing B1 channel");
+                       usb_control_msg(ucs->udev,
+                                       usb_sndctrlpipe(ucs->udev, 0),
+                                       HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ,
+                                       0, 0, NULL, 0, BAS_TIMEOUT);
+               }
+               if (ucs->basstate & BS_B2OPEN) {
+                       gig_dbg(DEBUG_INIT, "closing B2 channel");
+                       usb_control_msg(ucs->udev,
+                                       usb_sndctrlpipe(ucs->udev, 0),
+                                       HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ,
+                                       0, 0, NULL, 0, BAS_TIMEOUT);
+               }
+               if (ucs->basstate & BS_ATOPEN) {
+                       gig_dbg(DEBUG_INIT, "closing AT channel");
+                       usb_control_msg(ucs->udev,
+                                       usb_sndctrlpipe(ucs->udev, 0),
+                                       HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ,
+                                       0, 0, NULL, 0, BAS_TIMEOUT);
+               }
+               ucs->basstate = 0;
        }
-       atomic_set(&ucs->basstate, 0);
 
        /* deregister this driver with the USB subsystem */
        usb_deregister(&gigaset_usb_driver);
        /* this will call the disconnect-callback */
        /* from now on, no disconnect/probe callback should be running */
 
-       gigaset_freecs(cardstate);
-       cardstate = NULL;
        gigaset_freedriver(driver);
        driver = NULL;
 }
index acd417197d03dd6f46078bff2eff31fb05bf5414..aacedec4986fc7e98cc9f827b935274acc645a41 100644 (file)
@@ -31,7 +31,6 @@ MODULE_PARM_DESC(debug, "debug level");
 /* driver state flags */
 #define VALID_MINOR    0x01
 #define VALID_ID       0x02
-#define ASSIGNED       0x04
 
 void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
                        size_t len, const unsigned char *buf)
@@ -178,7 +177,7 @@ int gigaset_get_channel(struct bc_state *bcs)
        unsigned long flags;
 
        spin_lock_irqsave(&bcs->cs->lock, flags);
-       if (bcs->use_count) {
+       if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) {
                gig_dbg(DEBUG_ANY, "could not allocate channel %d",
                        bcs->channel);
                spin_unlock_irqrestore(&bcs->cs->lock, flags);
@@ -203,6 +202,7 @@ void gigaset_free_channel(struct bc_state *bcs)
        }
        --bcs->use_count;
        bcs->busy = 0;
+       module_put(bcs->cs->driver->owner);
        gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
        spin_unlock_irqrestore(&bcs->cs->lock, flags);
 }
@@ -356,31 +356,28 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv)
 {
        unsigned long flags;
        unsigned i;
+       struct cardstate *cs;
        struct cardstate *ret = NULL;
 
        spin_lock_irqsave(&drv->lock, flags);
+       if (drv->blocked)
+               goto exit;
        for (i = 0; i < drv->minors; ++i) {
-               if (!(drv->flags[i] & VALID_MINOR)) {
-                       if (try_module_get(drv->owner)) {
-                               drv->flags[i] = VALID_MINOR;
-                               ret = drv->cs + i;
-                       }
+               cs = drv->cs + i;
+               if (!(cs->flags & VALID_MINOR)) {
+                       cs->flags = VALID_MINOR;
+                       ret = cs;
                        break;
                }
        }
+exit:
        spin_unlock_irqrestore(&drv->lock, flags);
        return ret;
 }
 
 static void free_cs(struct cardstate *cs)
 {
-       unsigned long flags;
-       struct gigaset_driver *drv = cs->driver;
-       spin_lock_irqsave(&drv->lock, flags);
-       if (drv->flags[cs->minor_index] & VALID_MINOR)
-               module_put(drv->owner);
-       drv->flags[cs->minor_index] = 0;
-       spin_unlock_irqrestore(&drv->lock, flags);
+       cs->flags = 0;
 }
 
 static void make_valid(struct cardstate *cs, unsigned mask)
@@ -388,7 +385,7 @@ static void make_valid(struct cardstate *cs, unsigned mask)
        unsigned long flags;
        struct gigaset_driver *drv = cs->driver;
        spin_lock_irqsave(&drv->lock, flags);
-       drv->flags[cs->minor_index] |= mask;
+       cs->flags |= mask;
        spin_unlock_irqrestore(&drv->lock, flags);
 }
 
@@ -397,7 +394,7 @@ static void make_invalid(struct cardstate *cs, unsigned mask)
        unsigned long flags;
        struct gigaset_driver *drv = cs->driver;
        spin_lock_irqsave(&drv->lock, flags);
-       drv->flags[cs->minor_index] &= ~mask;
+       cs->flags &= ~mask;
        spin_unlock_irqrestore(&drv->lock, flags);
 }
 
@@ -501,11 +498,11 @@ static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
                               struct cardstate *cs, int inputstate)
 /* inbuf->read must be allocated before! */
 {
-       atomic_set(&inbuf->head, 0);
-       atomic_set(&inbuf->tail, 0);
+       inbuf->head = 0;
+       inbuf->tail = 0;
        inbuf->cs = cs;
        inbuf->bcs = bcs; /*base driver: NULL*/
-       inbuf->rcvbuf = NULL; //FIXME
+       inbuf->rcvbuf = NULL;
        inbuf->inputstate = inputstate;
 }
 
@@ -521,8 +518,8 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
                return 0;
 
        bytesleft = numbytes;
-       tail = atomic_read(&inbuf->tail);
-       head = atomic_read(&inbuf->head);
+       tail = inbuf->tail;
+       head = inbuf->head;
        gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
 
        while (bytesleft) {
@@ -546,7 +543,7 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
                src += n;
        }
        gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
-       atomic_set(&inbuf->tail, tail);
+       inbuf->tail = tail;
        return numbytes != bytesleft;
 }
 EXPORT_SYMBOL_GPL(gigaset_fill_inbuf);
@@ -668,7 +665,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
 
        tasklet_init(&cs->event_tasklet, &gigaset_handle_event,
                     (unsigned long) cs);
-       atomic_set(&cs->commands_pending, 0);
+       cs->commands_pending = 0;
        cs->cur_at_seq = 0;
        cs->gotfwver = -1;
        cs->open_count = 0;
@@ -688,8 +685,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
        init_waitqueue_head(&cs->waitqueue);
        cs->waiting = 0;
 
-       atomic_set(&cs->mode, M_UNKNOWN);
-       atomic_set(&cs->mstate, MS_UNINITIALIZED);
+       cs->mode = M_UNKNOWN;
+       cs->mstate = MS_UNINITIALIZED;
 
        for (i = 0; i < channels; ++i) {
                gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
@@ -806,8 +803,8 @@ static void cleanup_cs(struct cardstate *cs)
 
        spin_lock_irqsave(&cs->lock, flags);
 
-       atomic_set(&cs->mode, M_UNKNOWN);
-       atomic_set(&cs->mstate, MS_UNINITIALIZED);
+       cs->mode = M_UNKNOWN;
+       cs->mstate = MS_UNINITIALIZED;
 
        clear_at_state(&cs->at_state);
        dealloc_at_states(cs);
@@ -817,8 +814,8 @@ static void cleanup_cs(struct cardstate *cs)
        kfree(cs->inbuf->rcvbuf);
        cs->inbuf->rcvbuf = NULL;
        cs->inbuf->inputstate = INS_command;
-       atomic_set(&cs->inbuf->head, 0);
-       atomic_set(&cs->inbuf->tail, 0);
+       cs->inbuf->head = 0;
+       cs->inbuf->tail = 0;
 
        cb = cs->cmdbuf;
        while (cb) {
@@ -832,7 +829,7 @@ static void cleanup_cs(struct cardstate *cs)
        cs->gotfwver = -1;
        cs->dle = 0;
        cs->cur_at_seq = 0;
-       atomic_set(&cs->commands_pending, 0);
+       cs->commands_pending = 0;
        cs->cbytes = 0;
 
        spin_unlock_irqrestore(&cs->lock, flags);
@@ -862,7 +859,7 @@ int gigaset_start(struct cardstate *cs)
        cs->connected = 1;
        spin_unlock_irqrestore(&cs->lock, flags);
 
-       if (atomic_read(&cs->mstate) != MS_LOCKED) {
+       if (cs->mstate != MS_LOCKED) {
                cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
                cs->ops->baud_rate(cs, B115200);
                cs->ops->set_line_ctrl(cs, CS8);
@@ -893,10 +890,17 @@ error:
 }
 EXPORT_SYMBOL_GPL(gigaset_start);
 
-void gigaset_shutdown(struct cardstate *cs)
+/* gigaset_shutdown
+ * check if a device is associated to the cardstate structure and stop it
+ * return value: 0 if ok, -1 if no device was associated
+ */
+int gigaset_shutdown(struct cardstate *cs)
 {
        mutex_lock(&cs->mutex);
 
+       if (!(cs->flags & VALID_MINOR))
+               return -1;
+
        cs->waiting = 1;
 
        if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
@@ -913,6 +917,7 @@ void gigaset_shutdown(struct cardstate *cs)
 
 exit:
        mutex_unlock(&cs->mutex);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(gigaset_shutdown);
 
@@ -954,13 +959,11 @@ struct cardstate *gigaset_get_cs_by_id(int id)
        list_for_each_entry(drv, &drivers, list) {
                spin_lock(&drv->lock);
                for (i = 0; i < drv->minors; ++i) {
-                       if (drv->flags[i] & VALID_ID) {
-                               cs = drv->cs + i;
-                               if (cs->myid == id)
-                                       ret = cs;
-                       }
-                       if (ret)
+                       cs = drv->cs + i;
+                       if ((cs->flags & VALID_ID) && cs->myid == id) {
+                               ret = cs;
                                break;
+                       }
                }
                spin_unlock(&drv->lock);
                if (ret)
@@ -983,10 +986,9 @@ void gigaset_debugdrivers(void)
                spin_lock(&drv->lock);
                for (i = 0; i < drv->minors; ++i) {
                        gig_dbg(DEBUG_DRIVER, "  index %u", i);
-                       gig_dbg(DEBUG_DRIVER, "    flags 0x%02x",
-                               drv->flags[i]);
                        cs = drv->cs + i;
                        gig_dbg(DEBUG_DRIVER, "    cardstate %p", cs);
+                       gig_dbg(DEBUG_DRIVER, "    flags 0x%02x", cs->flags);
                        gig_dbg(DEBUG_DRIVER, "    minor_index %u",
                                cs->minor_index);
                        gig_dbg(DEBUG_DRIVER, "    driver %p", cs->driver);
@@ -1010,7 +1012,7 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
                        continue;
                index = minor - drv->minor;
                spin_lock(&drv->lock);
-               if (drv->flags[index] & VALID_MINOR)
+               if (drv->cs[index].flags & VALID_MINOR)
                        ret = drv->cs + index;
                spin_unlock(&drv->lock);
                if (ret)
@@ -1038,7 +1040,6 @@ void gigaset_freedriver(struct gigaset_driver *drv)
        gigaset_if_freedriver(drv);
 
        kfree(drv->cs);
-       kfree(drv->flags);
        kfree(drv);
 }
 EXPORT_SYMBOL_GPL(gigaset_freedriver);
@@ -1080,12 +1081,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
        if (!drv->cs)
                goto error;
 
-       drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);
-       if (!drv->flags)
-               goto error;
-
        for (i = 0; i < minors; ++i) {
-               drv->flags[i] = 0;
+               drv->cs[i].flags = 0;
                drv->cs[i].driver = drv;
                drv->cs[i].ops = drv->ops;
                drv->cs[i].minor_index = i;
@@ -1106,53 +1103,9 @@ error:
 }
 EXPORT_SYMBOL_GPL(gigaset_initdriver);
 
-/* For drivers without fixed assignment device<->cardstate (usb) */
-struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv)
-{
-       unsigned long flags;
-       struct cardstate *cs = NULL;
-       unsigned i;
-
-       spin_lock_irqsave(&drv->lock, flags);
-       if (drv->blocked)
-               goto exit;
-       for (i = 0; i < drv->minors; ++i) {
-               if ((drv->flags[i] & VALID_MINOR) &&
-                   !(drv->flags[i] & ASSIGNED)) {
-                       drv->flags[i] |= ASSIGNED;
-                       cs = drv->cs + i;
-                       break;
-               }
-       }
-exit:
-       spin_unlock_irqrestore(&drv->lock, flags);
-       return cs;
-}
-EXPORT_SYMBOL_GPL(gigaset_getunassignedcs);
-
-void gigaset_unassign(struct cardstate *cs)
-{
-       unsigned long flags;
-       unsigned *minor_flags;
-       struct gigaset_driver *drv;
-
-       if (!cs)
-               return;
-       drv = cs->driver;
-       spin_lock_irqsave(&drv->lock, flags);
-       minor_flags = drv->flags + cs->minor_index;
-       if (*minor_flags & VALID_MINOR)
-               *minor_flags &= ~ASSIGNED;
-       spin_unlock_irqrestore(&drv->lock, flags);
-}
-EXPORT_SYMBOL_GPL(gigaset_unassign);
-
 void gigaset_blockdriver(struct gigaset_driver *drv)
 {
-       unsigned long flags;
-       spin_lock_irqsave(&drv->lock, flags);
        drv->blocked = 1;
-       spin_unlock_irqrestore(&drv->lock, flags);
 }
 EXPORT_SYMBOL_GPL(gigaset_blockdriver);
 
index cec1ef342fcc31369ebf0f1a7c2f8a56437b5dff..5cbf64d850eefbbb4405d670d969f5938e38148e 100644 (file)
@@ -735,7 +735,7 @@ static void disconnect(struct at_state_t **at_state_p)
        /* revert to selected idle mode */
        if (!cs->cidmode) {
                cs->at_state.pending_commands |= PC_UMMODE;
-               atomic_set(&cs->commands_pending, 1); //FIXME
+               cs->commands_pending = 1;
                gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
        }
        spin_unlock_irqrestore(&cs->lock, flags);
@@ -793,15 +793,15 @@ static void init_failed(struct cardstate *cs, int mode)
        struct at_state_t *at_state;
 
        cs->at_state.pending_commands &= ~PC_INIT;
-       atomic_set(&cs->mode, mode);
-       atomic_set(&cs->mstate, MS_UNINITIALIZED);
+       cs->mode = mode;
+       cs->mstate = MS_UNINITIALIZED;
        gigaset_free_channels(cs);
        for (i = 0; i < cs->channels; ++i) {
                at_state = &cs->bcs[i].at_state;
                if (at_state->pending_commands & PC_CID) {
                        at_state->pending_commands &= ~PC_CID;
                        at_state->pending_commands |= PC_NOCID;
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                }
        }
 }
@@ -812,11 +812,11 @@ static void schedule_init(struct cardstate *cs, int state)
                gig_dbg(DEBUG_CMD, "not scheduling PC_INIT again");
                return;
        }
-       atomic_set(&cs->mstate, state);
-       atomic_set(&cs->mode, M_UNKNOWN);
+       cs->mstate = state;
+       cs->mode = M_UNKNOWN;
        gigaset_block_channels(cs);
        cs->at_state.pending_commands |= PC_INIT;
-       atomic_set(&cs->commands_pending, 1);
+       cs->commands_pending = 1;
        gig_dbg(DEBUG_CMD, "Scheduling PC_INIT");
 }
 
@@ -953,13 +953,13 @@ static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_ind
 
        at_state->pending_commands |= PC_CID;
        gig_dbg(DEBUG_CMD, "Scheduling PC_CID");
-       atomic_set(&cs->commands_pending, 1);
+       cs->commands_pending = 1;
        return;
 
 error:
        at_state->pending_commands |= PC_NOCID;
        gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID");
-       atomic_set(&cs->commands_pending, 1);
+       cs->commands_pending = 1;
        return;
 }
 
@@ -973,12 +973,12 @@ static void start_accept(struct at_state_t *at_state)
        if (retval == 0) {
                at_state->pending_commands |= PC_ACCEPT;
                gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
        } else {
-               //FIXME
+               /* error reset */
                at_state->pending_commands |= PC_HUP;
                gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
        }
 }
 
@@ -986,7 +986,7 @@ static void do_start(struct cardstate *cs)
 {
        gigaset_free_channels(cs);
 
-       if (atomic_read(&cs->mstate) != MS_LOCKED)
+       if (cs->mstate != MS_LOCKED)
                schedule_init(cs, MS_INIT);
 
        cs->isdn_up = 1;
@@ -1000,9 +1000,9 @@ static void do_start(struct cardstate *cs)
 
 static void finish_shutdown(struct cardstate *cs)
 {
-       if (atomic_read(&cs->mstate) != MS_LOCKED) {
-               atomic_set(&cs->mstate, MS_UNINITIALIZED);
-               atomic_set(&cs->mode, M_UNKNOWN);
+       if (cs->mstate != MS_LOCKED) {
+               cs->mstate = MS_UNINITIALIZED;
+               cs->mode = M_UNKNOWN;
        }
 
        /* Tell the LL that the device is not available .. */
@@ -1022,10 +1022,10 @@ static void do_shutdown(struct cardstate *cs)
 {
        gigaset_block_channels(cs);
 
-       if (atomic_read(&cs->mstate) == MS_READY) {
-               atomic_set(&cs->mstate, MS_SHUTDOWN);
+       if (cs->mstate == MS_READY) {
+               cs->mstate = MS_SHUTDOWN;
                cs->at_state.pending_commands |= PC_SHUTDOWN;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                gig_dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN");
        } else
                finish_shutdown(cs);
@@ -1120,7 +1120,7 @@ static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
                 * In fact it doesn't.
                 */
                at_state->pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                break;
        }
 }
@@ -1130,7 +1130,7 @@ static int do_lock(struct cardstate *cs)
        int mode;
        int i;
 
-       switch (atomic_read(&cs->mstate)) {
+       switch (cs->mstate) {
        case MS_UNINITIALIZED:
        case MS_READY:
                if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) ||
@@ -1152,20 +1152,20 @@ static int do_lock(struct cardstate *cs)
                return -EBUSY;
        }
 
-       mode = atomic_read(&cs->mode);
-       atomic_set(&cs->mstate, MS_LOCKED);
-       atomic_set(&cs->mode, M_UNKNOWN);
+       mode = cs->mode;
+       cs->mstate = MS_LOCKED;
+       cs->mode = M_UNKNOWN;
 
        return mode;
 }
 
 static int do_unlock(struct cardstate *cs)
 {
-       if (atomic_read(&cs->mstate) != MS_LOCKED)
+       if (cs->mstate != MS_LOCKED)
                return -EINVAL;
 
-       atomic_set(&cs->mstate, MS_UNINITIALIZED);
-       atomic_set(&cs->mode, M_UNKNOWN);
+       cs->mstate = MS_UNINITIALIZED;
+       cs->mode = M_UNKNOWN;
        gigaset_free_channels(cs);
        if (cs->connected)
                schedule_init(cs, MS_INIT);
@@ -1198,17 +1198,17 @@ static void do_action(int action, struct cardstate *cs,
        case ACT_INIT:
                cs->at_state.pending_commands &= ~PC_INIT;
                cs->cur_at_seq = SEQ_NONE;
-               atomic_set(&cs->mode, M_UNIMODEM);
+               cs->mode = M_UNIMODEM;
                spin_lock_irqsave(&cs->lock, flags);
                if (!cs->cidmode) {
                        spin_unlock_irqrestore(&cs->lock, flags);
                        gigaset_free_channels(cs);
-                       atomic_set(&cs->mstate, MS_READY);
+                       cs->mstate = MS_READY;
                        break;
                }
                spin_unlock_irqrestore(&cs->lock, flags);
                cs->at_state.pending_commands |= PC_CIDMODE;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
                break;
        case ACT_FAILINIT:
@@ -1234,22 +1234,20 @@ static void do_action(int action, struct cardstate *cs,
                        | INS_command;
                break;
        case ACT_CMODESET:
-               if (atomic_read(&cs->mstate) == MS_INIT ||
-                   atomic_read(&cs->mstate) == MS_RECOVER) {
+               if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) {
                        gigaset_free_channels(cs);
-                       atomic_set(&cs->mstate, MS_READY);
+                       cs->mstate = MS_READY;
                }
-               atomic_set(&cs->mode, M_CID);
+               cs->mode = M_CID;
                cs->cur_at_seq = SEQ_NONE;
                break;
        case ACT_UMODESET:
-               atomic_set(&cs->mode, M_UNIMODEM);
+               cs->mode = M_UNIMODEM;
                cs->cur_at_seq = SEQ_NONE;
                break;
        case ACT_FAILCMODE:
                cs->cur_at_seq = SEQ_NONE;
-               if (atomic_read(&cs->mstate) == MS_INIT ||
-                   atomic_read(&cs->mstate) == MS_RECOVER) {
+               if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) {
                        init_failed(cs, M_UNKNOWN);
                        break;
                }
@@ -1307,7 +1305,7 @@ static void do_action(int action, struct cardstate *cs,
        case ACT_CONNECT:
                if (cs->onechannel) {
                        at_state->pending_commands |= PC_DLE1;
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                        break;
                }
                bcs->chstate |= CHS_D_UP;
@@ -1333,7 +1331,7 @@ static void do_action(int action, struct cardstate *cs,
                         * DLE only used for M10x with one B channel.
                         */
                        at_state->pending_commands |= PC_DLE0;
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                } else
                        disconnect(p_at_state);
                break;
@@ -1369,7 +1367,7 @@ static void do_action(int action, struct cardstate *cs,
                         "Could not enter DLE mode. Trying to hang up.\n");
                channel = cs->curchannel;
                cs->bcs[channel].at_state.pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                break;
 
        case ACT_CID: /* got cid; start dialing */
@@ -1379,7 +1377,7 @@ static void do_action(int action, struct cardstate *cs,
                        cs->bcs[channel].at_state.cid = ev->parameter;
                        cs->bcs[channel].at_state.pending_commands |=
                                PC_DIAL;
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                        break;
                }
                /* fall through */
@@ -1411,14 +1409,14 @@ static void do_action(int action, struct cardstate *cs,
        case ACT_ABORTDIAL:     /* error/timeout during dial preparation */
                cs->cur_at_seq = SEQ_NONE;
                at_state->pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                break;
 
        case ACT_REMOTEREJECT:  /* DISCONNECT_IND after dialling */
        case ACT_CONNTIMEOUT:   /* timeout waiting for ZSAU=ACTIVE */
        case ACT_REMOTEHUP:     /* DISCONNECT_IND with established connection */
                at_state->pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                break;
        case ACT_GETSTRING: /* warning: RING, ZDLE, ...
                               are not handled properly anymore */
@@ -1515,7 +1513,7 @@ static void do_action(int action, struct cardstate *cs,
                break;
        case ACT_HUP:
                at_state->pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
                break;
 
@@ -1558,7 +1556,7 @@ static void do_action(int action, struct cardstate *cs,
                                cs->at_state.pending_commands |= PC_UMMODE;
                                gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
                        }
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                }
                spin_unlock_irqrestore(&cs->lock, flags);
                cs->waiting = 0;
@@ -1741,7 +1739,7 @@ static void process_command_flags(struct cardstate *cs)
        int sequence;
        unsigned long flags;
 
-       atomic_set(&cs->commands_pending, 0);
+       cs->commands_pending = 0;
 
        if (cs->cur_at_seq) {
                gig_dbg(DEBUG_CMD, "not searching scheduled commands: busy");
@@ -1779,7 +1777,7 @@ static void process_command_flags(struct cardstate *cs)
                                ~(PC_DLE1 | PC_ACCEPT | PC_DIAL);
                        if (at_state->cid > 0)
                                at_state->pending_commands |= PC_HUP;
-                       if (atomic_read(&cs->mstate) == MS_RECOVER) {
+                       if (cs->mstate == MS_RECOVER) {
                                if (at_state->pending_commands & PC_CID) {
                                        at_state->pending_commands |= PC_NOCID;
                                        at_state->pending_commands &= ~PC_CID;
@@ -1793,7 +1791,7 @@ static void process_command_flags(struct cardstate *cs)
        if (cs->at_state.pending_commands == PC_UMMODE
            && !cs->cidmode
            && list_empty(&cs->temp_at_states)
-           && atomic_read(&cs->mode) == M_CID) {
+           && cs->mode == M_CID) {
                sequence = SEQ_UMMODE;
                at_state = &cs->at_state;
                for (i = 0; i < cs->channels; ++i) {
@@ -1860,7 +1858,7 @@ static void process_command_flags(struct cardstate *cs)
        }
        if (cs->at_state.pending_commands & PC_CIDMODE) {
                cs->at_state.pending_commands &= ~PC_CIDMODE;
-               if (atomic_read(&cs->mode) == M_UNIMODEM) {
+               if (cs->mode == M_UNIMODEM) {
                        cs->retry_count = 1;
                        schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE);
                        return;
@@ -1886,11 +1884,11 @@ static void process_command_flags(struct cardstate *cs)
                        return;
                }
                if (bcs->at_state.pending_commands & PC_CID) {
-                       switch (atomic_read(&cs->mode)) {
+                       switch (cs->mode) {
                        case M_UNIMODEM:
                                cs->at_state.pending_commands |= PC_CIDMODE;
                                gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
-                               atomic_set(&cs->commands_pending, 1);
+                               cs->commands_pending = 1;
                                return;
 #ifdef GIG_MAYINITONDIAL
                        case M_UNKNOWN:
@@ -1926,7 +1924,7 @@ static void process_events(struct cardstate *cs)
        for (i = 0; i < 2 * MAX_EVENTS; ++i) {
                tail = cs->ev_tail;
                if (tail == head) {
-                       if (!check_flags && !atomic_read(&cs->commands_pending))
+                       if (!check_flags && !cs->commands_pending)
                                break;
                        check_flags = 0;
                        spin_unlock_irqrestore(&cs->ev_lock, flags);
@@ -1934,7 +1932,7 @@ static void process_events(struct cardstate *cs)
                        spin_lock_irqsave(&cs->ev_lock, flags);
                        tail = cs->ev_tail;
                        if (tail == head) {
-                               if (!atomic_read(&cs->commands_pending))
+                               if (!cs->commands_pending)
                                        break;
                                continue;
                        }
@@ -1971,7 +1969,7 @@ void gigaset_handle_event(unsigned long data)
        struct cardstate *cs = (struct cardstate *) data;
 
        /* handle incoming data on control/common channel */
-       if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) {
+       if (cs->inbuf->head != cs->inbuf->tail) {
                gig_dbg(DEBUG_INTR, "processing new data");
                cs->ops->handle_input(cs->inbuf);
        }
index 02bdaf22d7ea10b28cbe779dd6097ce52b318b17..f365993161fcc6a2a8432e4d890c9ddef45b628a 100644 (file)
 
 extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */
 
-/* any combination of these can be given with the 'debug=' parameter to insmod,
- * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and
- * DEBUG_INTR.
- */
+/* debug flags, combine by adding/bitwise OR */
 enum debuglevel {
-       DEBUG_REG         = 0x0002, /* serial port I/O register operations */
-       DEBUG_OPEN        = 0x0004, /* open/close serial port */
-       DEBUG_INTR        = 0x0008, /* interrupt processing */
-       DEBUG_INTR_DUMP   = 0x0010, /* Activating hexdump debug output on
-                                      interrupt requests, not available as
-                                      run-time option */
+       DEBUG_INTR        = 0x00008, /* interrupt processing */
        DEBUG_CMD         = 0x00020, /* sent/received LL commands */
        DEBUG_STREAM      = 0x00040, /* application data stream I/O events */
        DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
        DEBUG_LLDATA      = 0x00100, /* sent/received LL data */
-       DEBUG_INTR_0      = 0x00200, /* serial port interrupt processing */
        DEBUG_DRIVER      = 0x00400, /* driver structure */
        DEBUG_HDLC        = 0x00800, /* M10x HDLC processing */
        DEBUG_WRITE       = 0x01000, /* M105 data write */
@@ -93,7 +84,7 @@ enum debuglevel {
        DEBUG_MCMD        = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */
        DEBUG_INIT        = 0x08000, /* (de)allocation+initialization of data
                                        structures */
-       DEBUG_LOCK        = 0x10000, /* semaphore operations */
+       DEBUG_SUSPEND     = 0x10000, /* suspend/resume processing */
        DEBUG_OUTPUT      = 0x20000, /* output to device */
        DEBUG_ISO         = 0x40000, /* isochronous transfers */
        DEBUG_IF          = 0x80000, /* character device operations */
@@ -191,6 +182,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
 #define        HD_OPEN_ATCHANNEL               (0x28)          // 3070
 #define        HD_CLOSE_ATCHANNEL              (0x29)          // 3070
 
+/* number of B channels supported by base driver */
+#define BAS_CHANNELS   2
+
 /* USB frames for isochronous transfer */
 #define BAS_FRAMETIME  1       /* number of milliseconds between frames */
 #define BAS_NUMFRAMES  8       /* number of frames per URB */
@@ -313,7 +307,7 @@ struct inbuf_t {
        struct bc_state         *bcs;
        struct cardstate        *cs;
        int                     inputstate;
-       atomic_t                head, tail;
+       int                     head, tail;
        unsigned char           data[RBUFSIZE];
 };
 
@@ -335,9 +329,9 @@ struct inbuf_t {
  *   are also filled with that value
  */
 struct isowbuf_t {
-       atomic_t        read;
-       atomic_t        nextread;
-       atomic_t        write;
+       int             read;
+       int             nextread;
+       int             write;
        atomic_t        writesem;
        int             wbits;
        unsigned char   data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD];
@@ -350,11 +344,13 @@ struct isowbuf_t {
  * - urb: pointer to the URB itself
  * - bcs: pointer to the B Channel control structure
  * - limit: end of write buffer area covered by this URB
+ * - status: URB completion status
  */
 struct isow_urbctx_t {
        struct urb *urb;
        struct bc_state *bcs;
        int limit;
+       int status;
 };
 
 /* AT state structure
@@ -439,14 +435,15 @@ struct cardstate {
        unsigned minor_index;
        struct device *dev;
        struct device *tty_dev;
+       unsigned flags;
 
        const struct gigaset_ops *ops;
 
        /* Stuff to handle communication */
        wait_queue_head_t waitqueue;
        int waiting;
-       atomic_t mode;                  /* see M_XXXX */
-       atomic_t mstate;                /* Modem state: see MS_XXXX */
+       int mode;                       /* see M_XXXX */
+       int mstate;                     /* Modem state: see MS_XXXX */
                                        /* only changed by the event layer */
        int cmd_result;
 
@@ -503,7 +500,7 @@ struct cardstate {
                                           processed */
        int curchannel;                 /* channel those commands are meant
                                           for */
-       atomic_t commands_pending;      /* flag(s) in xxx.commands_pending have
+       int commands_pending;           /* flag(s) in xxx.commands_pending have
                                           been set */
        struct tasklet_struct event_tasklet;
                                        /* tasklet for serializing AT commands.
@@ -543,7 +540,6 @@ struct gigaset_driver {
        unsigned minor;
        unsigned minors;
        struct cardstate *cs;
-       unsigned *flags;
        int blocked;
 
        const struct gigaset_ops *ops;
@@ -559,7 +555,7 @@ struct cmdbuf_t {
 
 struct bas_bc_state {
        /* isochronous output state */
-       atomic_t        running;
+       int             running;
        atomic_t        corrbytes;
        spinlock_t      isooutlock;
        struct isow_urbctx_t    isoouturbs[BAS_OUTURBS];
@@ -574,6 +570,7 @@ struct bas_bc_state {
        struct urb *isoinurbs[BAS_INURBS];
        unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS];
        struct urb *isoindone;          /* completed isoc read URB */
+       int isoinstatus;                /* status of completed URB */
        int loststatus;                 /* status of dropped URB */
        unsigned isoinlost;             /* number of bytes lost */
        /* state of bit unstuffing algorithm
@@ -770,10 +767,6 @@ void gigaset_freedriver(struct gigaset_driver *drv);
 void gigaset_debugdrivers(void);
 struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
 struct cardstate *gigaset_get_cs_by_id(int id);
-
-/* For drivers without fixed assignment device<->cardstate (usb) */
-struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv);
-void gigaset_unassign(struct cardstate *cs);
 void gigaset_blockdriver(struct gigaset_driver *drv);
 
 /* Allocate and initialize card state. Calls hardware dependent
@@ -792,7 +785,7 @@ int gigaset_start(struct cardstate *cs);
 void gigaset_stop(struct cardstate *cs);
 
 /* Tell common.c that the driver is being unloaded. */
-void gigaset_shutdown(struct cardstate *cs);
+int gigaset_shutdown(struct cardstate *cs);
 
 /* Tell common.c that an skb has been sent. */
 void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
index eb50f3dab5f77908ecc6111da0911b1a3370b9c2..af195b07c191b6b02b09c57548f6477334672a92 100644 (file)
@@ -28,12 +28,11 @@ static int if_lock(struct cardstate *cs, int *arg)
                return -EINVAL;
 
        if (cmd < 0) {
-               *arg = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove?
+               *arg = cs->mstate == MS_LOCKED;
                return 0;
        }
 
-       if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
-           && cs->connected) {
+       if (!cmd && cs->mstate == MS_LOCKED && cs->connected) {
                cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
                cs->ops->baud_rate(cs, B115200);
                cs->ops->set_line_ctrl(cs, CS8);
@@ -104,7 +103,7 @@ static int if_config(struct cardstate *cs, int *arg)
        if (*arg != 1)
                return -EINVAL;
 
-       if (atomic_read(&cs->mstate) != MS_LOCKED)
+       if (cs->mstate != MS_LOCKED)
                return -EBUSY;
 
        if (!cs->connected) {
@@ -162,7 +161,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
        tty->driver_data = NULL;
 
        cs = gigaset_get_cs_by_tty(tty);
-       if (!cs)
+       if (!cs || !try_module_get(cs->driver->owner))
                return -ENODEV;
 
        if (mutex_lock_interruptible(&cs->mutex))
@@ -208,6 +207,8 @@ static void if_close(struct tty_struct *tty, struct file *filp)
        }
 
        mutex_unlock(&cs->mutex);
+
+       module_put(cs->driver->owner);
 }
 
 static int if_ioctl(struct tty_struct *tty, struct file *file,
@@ -364,7 +365,7 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
 
        if (!cs->open_count)
                warn("%s: device not opened", __func__);
-       else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+       else if (cs->mstate != MS_LOCKED) {
                warn("can't write to unlocked device");
                retval = -EBUSY;
        } else if (!cs->connected) {
@@ -398,9 +399,9 @@ static int if_write_room(struct tty_struct *tty)
 
        if (!cs->open_count)
                warn("%s: device not opened", __func__);
-       else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+       else if (cs->mstate != MS_LOCKED) {
                warn("can't write to unlocked device");
-               retval = -EBUSY; //FIXME
+               retval = -EBUSY;
        } else if (!cs->connected) {
                gig_dbg(DEBUG_ANY, "can't write to unplugged device");
                retval = -EBUSY; //FIXME
@@ -430,7 +431,7 @@ static int if_chars_in_buffer(struct tty_struct *tty)
 
        if (!cs->open_count)
                warn("%s: device not opened", __func__);
-       else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+       else if (cs->mstate != MS_LOCKED) {
                warn("can't write to unlocked device");
                retval = -EBUSY;
        } else if (!cs->connected) {
index e0505f238807ab4f3fbd285cb499bc15191f034f..e30a7773f93cefecdf315db52daf65c12948f4be 100644 (file)
@@ -23,9 +23,9 @@
  */
 void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle)
 {
-       atomic_set(&iwb->read, 0);
-       atomic_set(&iwb->nextread, 0);
-       atomic_set(&iwb->write, 0);
+       iwb->read = 0;
+       iwb->nextread = 0;
+       iwb->write = 0;
        atomic_set(&iwb->writesem, 1);
        iwb->wbits = 0;
        iwb->idle = idle;
@@ -39,8 +39,8 @@ static inline int isowbuf_freebytes(struct isowbuf_t *iwb)
 {
        int read, write, freebytes;
 
-       read = atomic_read(&iwb->read);
-       write = atomic_read(&iwb->write);
+       read = iwb->read;
+       write = iwb->write;
        if ((freebytes = read - write) > 0) {
                /* no wraparound: need padding space within regular area */
                return freebytes - BAS_OUTBUFPAD;
@@ -62,7 +62,7 @@ static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b)
        int read;
        if (a == b)
                return 0;
-       read = atomic_read(&iwb->read);
+       read = iwb->read;
        if (a < b) {
                if (a < read && read <= b)
                        return +1;
@@ -91,18 +91,18 @@ static inline int isowbuf_startwrite(struct isowbuf_t *iwb)
 #ifdef CONFIG_GIGASET_DEBUG
        gig_dbg(DEBUG_ISO,
                "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
-               __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits);
+               __func__, iwb->data[iwb->write], iwb->wbits);
 #endif
        return 1;
 }
 
 /* finish writing
- * release the write semaphore and update the maximum buffer fill level
+ * release the write semaphore
  * returns the current write position
  */
 static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
 {
-       int write = atomic_read(&iwb->write);
+       int write = iwb->write;
        atomic_inc(&iwb->writesem);
        return write;
 }
@@ -116,7 +116,7 @@ static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
  */
 static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
 {
-       int write = atomic_read(&iwb->write);
+       int write = iwb->write;
        data <<= iwb->wbits;
        data |= iwb->data[write];
        nbits += iwb->wbits;
@@ -128,7 +128,7 @@ static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
        }
        iwb->wbits = nbits;
        iwb->data[write] = data & 0xff;
-       atomic_set(&iwb->write, write);
+       iwb->write = write;
 }
 
 /* put final flag on HDLC bitstream
@@ -142,7 +142,7 @@ static inline void isowbuf_putflag(struct isowbuf_t *iwb)
        /* add two flags, thus reliably covering one byte */
        isowbuf_putbits(iwb, 0x7e7e, 8);
        /* recover the idle flag byte */
-       write = atomic_read(&iwb->write);
+       write = iwb->write;
        iwb->idle = iwb->data[write];
        gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
        /* mask extraneous bits in buffer */
@@ -160,8 +160,8 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
        int read, write, limit, src, dst;
        unsigned char pbyte;
 
-       read = atomic_read(&iwb->nextread);
-       write = atomic_read(&iwb->write);
+       read = iwb->nextread;
+       write = iwb->write;
        if (likely(read == write)) {
                /* return idle frame */
                return read < BAS_OUTBUFPAD ?
@@ -176,7 +176,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
                err("invalid size %d", size);
                return -EINVAL;
        }
-       src = atomic_read(&iwb->read);
+       src = iwb->read;
        if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
                     (read < src && limit >= src))) {
                err("isoc write buffer frame reservation violated");
@@ -191,7 +191,8 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
                        if (!isowbuf_startwrite(iwb))
                                return -EBUSY;
                        /* write position could have changed */
-                       if (limit >= (write = atomic_read(&iwb->write))) {
+                       write = iwb->write;
+                       if (limit >= write) {
                                pbyte = iwb->data[write]; /* save
                                                             partial byte */
                                limit = write + BAS_OUTBUFPAD;
@@ -213,7 +214,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
                                        __func__, pbyte, limit);
                                iwb->data[limit] = pbyte; /* restore
                                                             partial byte */
-                               atomic_set(&iwb->write, limit);
+                               iwb->write = limit;
                        }
                        isowbuf_donewrite(iwb);
                }
@@ -233,7 +234,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
                        limit = src;
                }
        }
-       atomic_set(&iwb->nextread, limit);
+       iwb->nextread = limit;
        return read;
 }
 
@@ -477,7 +478,7 @@ static inline int trans_buildframe(struct isowbuf_t *iwb,
        unsigned char c;
 
        if (unlikely(count <= 0))
-               return atomic_read(&iwb->write); /* better ideas? */
+               return iwb->write;
 
        if (isowbuf_freebytes(iwb) < count ||
            !isowbuf_startwrite(iwb)) {
@@ -486,13 +487,13 @@ static inline int trans_buildframe(struct isowbuf_t *iwb,
        }
 
        gig_dbg(DEBUG_STREAM, "put %d bytes", count);
-       write = atomic_read(&iwb->write);
+       write = iwb->write;
        do {
                c = bitrev8(*in++);
                iwb->data[write++] = c;
                write %= BAS_OUTBUFSIZE;
        } while (--count > 0);
-       atomic_set(&iwb->write, write);
+       iwb->write = write;
        iwb->idle = c;
 
        return isowbuf_donewrite(iwb);
@@ -947,8 +948,8 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
        unsigned tail, head, numbytes;
        unsigned char *src;
 
-       head = atomic_read(&inbuf->head);
-       while (head != (tail = atomic_read(&inbuf->tail))) {
+       head = inbuf->head;
+       while (head != (tail = inbuf->tail)) {
                gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
                if (head > tail)
                        tail = RBUFSIZE;
@@ -956,7 +957,7 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
                numbytes = tail - head;
                gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
 
-               if (atomic_read(&cs->mstate) == MS_LOCKED) {
+               if (cs->mstate == MS_LOCKED) {
                        gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
                                           numbytes, src);
                        gigaset_if_receive(inbuf->cs, src, numbytes);
@@ -970,7 +971,7 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
                if (head == RBUFSIZE)
                        head = 0;
                gig_dbg(DEBUG_INTR, "setting head to %u", head);
-               atomic_set(&inbuf->head, head);
+               inbuf->head = head;
        }
 }
 
index ea44302e6e7ecad6cb9a1e3b7f7f8ee94961a692..fceeb1d57682849b3e438e63a265d4fd036efe78 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/tty.h>
 #include <linux/poll.h>
+#include <linux/completion.h>
 
 /* Version Information */
 #define DRIVER_AUTHOR "Tilman Schmidt"
@@ -48,7 +49,7 @@ struct ser_cardstate {
        struct platform_device  dev;
        struct tty_struct       *tty;
        atomic_t                refcnt;
-       struct mutex            dead_mutex;
+       struct completion       dead_cmp;
 };
 
 static struct platform_driver device_driver = {
@@ -240,7 +241,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
        struct cmdbuf_t *cb;
        unsigned long flags;
 
-       gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+       gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
                           "CMD Transmit", len, buf);
 
@@ -498,7 +499,7 @@ static struct cardstate *cs_get(struct tty_struct *tty)
 static void cs_put(struct cardstate *cs)
 {
        if (atomic_dec_and_test(&cs->hw.ser->refcnt))
-               mutex_unlock(&cs->hw.ser->dead_mutex);
+               complete(&cs->hw.ser->dead_cmp);
 }
 
 /*
@@ -527,8 +528,8 @@ gigaset_tty_open(struct tty_struct *tty)
 
        cs->dev = &cs->hw.ser->dev.dev;
        cs->hw.ser->tty = tty;
-       mutex_init(&cs->hw.ser->dead_mutex);
        atomic_set(&cs->hw.ser->refcnt, 1);
+       init_completion(&cs->hw.ser->dead_cmp);
 
        tty->disc_data = cs;
 
@@ -536,14 +537,13 @@ gigaset_tty_open(struct tty_struct *tty)
         * startup system and notify the LL that we are ready to run
         */
        if (startmode == SM_LOCKED)
-               atomic_set(&cs->mstate, MS_LOCKED);
+               cs->mstate = MS_LOCKED;
        if (!gigaset_start(cs)) {
                tasklet_kill(&cs->write_tasklet);
                goto error;
        }
 
        gig_dbg(DEBUG_INIT, "Startup of HLL done");
-       mutex_lock(&cs->hw.ser->dead_mutex);
        return 0;
 
 error:
@@ -577,7 +577,7 @@ gigaset_tty_close(struct tty_struct *tty)
        else {
                /* wait for running methods to finish */
                if (!atomic_dec_and_test(&cs->hw.ser->refcnt))
-                       mutex_lock(&cs->hw.ser->dead_mutex);
+                       wait_for_completion(&cs->hw.ser->dead_cmp);
        }
 
        /* stop operations */
@@ -714,8 +714,8 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
                return;
        }
 
-       tail = atomic_read(&inbuf->tail);
-       head = atomic_read(&inbuf->head);
+       tail = inbuf->tail;
+       head = inbuf->head;
        gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes",
                head, tail, count);
 
@@ -742,7 +742,7 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
        }
 
        gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
-       atomic_set(&inbuf->tail, tail);
+       inbuf->tail = tail;
 
        /* Everything was received .. Push data into handler */
        gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
index ca4bee173cfb05e5857dffa3c9763ec559a803b6..77d20ab0cd4d422b31226c9093a08eedb22ad937 100644 (file)
@@ -104,12 +104,17 @@ MODULE_DEVICE_TABLE(usb, gigaset_table);
  * flags per packet.
  */
 
+/* functions called if a device of this driver is connected/disconnected */
 static int gigaset_probe(struct usb_interface *interface,
                         const struct usb_device_id *id);
 static void gigaset_disconnect(struct usb_interface *interface);
 
+/* functions called before/after suspend */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
+static int gigaset_resume(struct usb_interface *intf);
+static int gigaset_pre_reset(struct usb_interface *intf);
+
 static struct gigaset_driver *driver = NULL;
-static struct cardstate *cardstate = NULL;
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver gigaset_usb_driver = {
@@ -117,12 +122,17 @@ static struct usb_driver gigaset_usb_driver = {
        .probe =        gigaset_probe,
        .disconnect =   gigaset_disconnect,
        .id_table =     gigaset_table,
+       .suspend =      gigaset_suspend,
+       .resume =       gigaset_resume,
+       .reset_resume = gigaset_resume,
+       .pre_reset =    gigaset_pre_reset,
+       .post_reset =   gigaset_resume,
 };
 
 struct usb_cardstate {
        struct usb_device       *udev;          /* usb device pointer */
        struct usb_interface    *interface;     /* interface for this device */
-       atomic_t                busy;           /* bulk output in progress */
+       int                     busy;           /* bulk output in progress */
 
        /* Output buffer */
        unsigned char           *bulk_out_buffer;
@@ -314,7 +324,7 @@ static void gigaset_modem_fill(unsigned long data)
 
        gig_dbg(DEBUG_OUTPUT, "modem_fill");
 
-       if (atomic_read(&cs->hw.usb->busy)) {
+       if (cs->hw.usb->busy) {
                gig_dbg(DEBUG_OUTPUT, "modem_fill: busy");
                return;
        }
@@ -361,18 +371,13 @@ static void gigaset_read_int_callback(struct urb *urb)
 {
        struct inbuf_t *inbuf = urb->context;
        struct cardstate *cs = inbuf->cs;
-       int resubmit = 0;
+       int status = urb->status;
        int r;
        unsigned numbytes;
        unsigned char *src;
        unsigned long flags;
 
-       if (!urb->status) {
-               if (!cs->connected) {
-                       err("%s: disconnected", __func__); /* should never happen */
-                       return;
-               }
-
+       if (!status) {
                numbytes = urb->actual_length;
 
                if (numbytes) {
@@ -389,28 +394,26 @@ static void gigaset_read_int_callback(struct urb *urb)
                        }
                } else
                        gig_dbg(DEBUG_INTR, "Received zero block length");
-               resubmit = 1;
        } else {
                /* The urb might have been killed. */
-               gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
-                       __func__, urb->status);
-               if (urb->status != -ENOENT) { /* not killed */
-                       if (!cs->connected) {
-                               err("%s: disconnected", __func__); /* should never happen */
-                               return;
-                       }
-                       resubmit = 1;
-               }
+               gig_dbg(DEBUG_ANY, "%s - nonzero status received: %d",
+                       __func__, status);
+               if (status == -ENOENT || status == -ESHUTDOWN)
+                       /* killed or endpoint shutdown: don't resubmit */
+                       return;
        }
 
-       if (resubmit) {
-               spin_lock_irqsave(&cs->lock, flags);
-               r = cs->connected ? usb_submit_urb(urb, GFP_ATOMIC) : -ENODEV;
+       /* resubmit URB */
+       spin_lock_irqsave(&cs->lock, flags);
+       if (!cs->connected) {
                spin_unlock_irqrestore(&cs->lock, flags);
-               if (r)
-                       dev_err(cs->dev, "error %d when resubmitting urb.\n",
-                               -r);
+               err("%s: disconnected", __func__);
+               return;
        }
+       r = usb_submit_urb(urb, GFP_ATOMIC);
+       spin_unlock_irqrestore(&cs->lock, flags);
+       if (r)
+               dev_err(cs->dev, "error %d resubmitting URB\n", -r);
 }
 
 
@@ -418,19 +421,28 @@ static void gigaset_read_int_callback(struct urb *urb)
 static void gigaset_write_bulk_callback(struct urb *urb)
 {
        struct cardstate *cs = urb->context;
+       int status = urb->status;
        unsigned long flags;
 
-       if (urb->status)
+       switch (status) {
+       case 0:                 /* normal completion */
+               break;
+       case -ENOENT:           /* killed */
+               gig_dbg(DEBUG_ANY, "%s: killed", __func__);
+               cs->hw.usb->busy = 0;
+               return;
+       default:
                dev_err(cs->dev, "bulk transfer failed (status %d)\n",
-                       -urb->status);
+                       -status);
                /* That's all we can do. Communication problems
                   are handled by timeouts or network protocols. */
+       }
 
        spin_lock_irqsave(&cs->lock, flags);
        if (!cs->connected) {
                err("%s: not connected", __func__);
        } else {
-               atomic_set(&cs->hw.usb->busy, 0);
+               cs->hw.usb->busy = 0;
                tasklet_schedule(&cs->write_tasklet);
        }
        spin_unlock_irqrestore(&cs->lock, flags);
@@ -478,14 +490,14 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
 
                        cb->offset += count;
                        cb->len -= count;
-                       atomic_set(&ucs->busy, 1);
+                       ucs->busy = 1;
 
                        spin_lock_irqsave(&cs->lock, flags);
                        status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV;
                        spin_unlock_irqrestore(&cs->lock, flags);
 
                        if (status) {
-                               atomic_set(&ucs->busy, 0);
+                               ucs->busy = 0;
                                err("could not submit urb (error %d)\n",
                                    -status);
                                cb->len = 0; /* skip urb => remove cb+wakeup
@@ -504,7 +516,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
        struct cmdbuf_t *cb;
        unsigned long flags;
 
-       gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+       gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
                           "CMD Transmit", len, buf);
 
@@ -641,7 +653,7 @@ static int write_modem(struct cardstate *cs)
        count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
        skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count);
        skb_pull(bcs->tx_skb, count);
-       atomic_set(&ucs->busy, 1);
+       ucs->busy = 1;
        gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
 
        spin_lock_irqsave(&cs->lock, flags);
@@ -659,7 +671,7 @@ static int write_modem(struct cardstate *cs)
 
        if (ret) {
                err("could not submit urb (error %d)\n", -ret);
-               atomic_set(&ucs->busy, 0);
+               ucs->busy = 0;
        }
 
        if (!bcs->tx_skb->len) {
@@ -680,53 +692,44 @@ static int gigaset_probe(struct usb_interface *interface,
 {
        int retval;
        struct usb_device *udev = interface_to_usbdev(interface);
-       unsigned int ifnum;
-       struct usb_host_interface *hostif;
+       struct usb_host_interface *hostif = interface->cur_altsetting;
        struct cardstate *cs = NULL;
        struct usb_cardstate *ucs = NULL;
        struct usb_endpoint_descriptor *endpoint;
        int buffer_size;
-       int alt;
 
-       gig_dbg(DEBUG_ANY,
-               "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
-               __func__, le16_to_cpu(udev->descriptor.idVendor),
-               le16_to_cpu(udev->descriptor.idProduct));
-
-       retval = -ENODEV; //FIXME
+       gig_dbg(DEBUG_ANY, "%s: Check if device matches ...", __func__);
 
        /* See if the device offered us matches what we can accept */
        if ((le16_to_cpu(udev->descriptor.idVendor)  != USB_M105_VENDOR_ID) ||
-           (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID))
+           (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) {
+               gig_dbg(DEBUG_ANY, "device ID (0x%x, 0x%x) not for me - skip",
+                       le16_to_cpu(udev->descriptor.idVendor),
+                       le16_to_cpu(udev->descriptor.idProduct));
                return -ENODEV;
-
-       /* this starts to become ascii art... */
-       hostif = interface->cur_altsetting;
-       alt = hostif->desc.bAlternateSetting;
-       ifnum = hostif->desc.bInterfaceNumber; // FIXME ?
-
-       if (alt != 0 || ifnum != 0) {
-               dev_warn(&udev->dev, "ifnum %d, alt %d\n", ifnum, alt);
+       }
+       if (hostif->desc.bInterfaceNumber != 0) {
+               gig_dbg(DEBUG_ANY, "interface %d not for me - skip",
+                       hostif->desc.bInterfaceNumber);
+               return -ENODEV;
+       }
+       if (hostif->desc.bAlternateSetting != 0) {
+               dev_notice(&udev->dev, "unsupported altsetting %d - skip",
+                          hostif->desc.bAlternateSetting);
                return -ENODEV;
        }
-
-       /* Reject application specific intefaces
-        *
-        */
        if (hostif->desc.bInterfaceClass != 255) {
-               dev_info(&udev->dev,
-               "%s: Device matched but iface_desc[%d]->bInterfaceClass==%d!\n",
-                        __func__, ifnum, hostif->desc.bInterfaceClass);
+               dev_notice(&udev->dev, "unsupported interface class %d - skip",
+                          hostif->desc.bInterfaceClass);
                return -ENODEV;
        }
 
        dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
 
-       cs = gigaset_getunassignedcs(driver);
-       if (!cs) {
-               dev_warn(&udev->dev, "no free cardstate\n");
+       /* allocate memory for our device state and intialize it */
+       cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
+       if (!cs)
                return -ENODEV;
-       }
        ucs = cs->hw.usb;
 
        /* save off device structure ptrs for later use */
@@ -759,7 +762,7 @@ static int gigaset_probe(struct usb_interface *interface,
 
        endpoint = &hostif->endpoint[1].desc;
 
-       atomic_set(&ucs->busy, 0);
+       ucs->busy = 0;
 
        ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!ucs->read_urb) {
@@ -792,7 +795,7 @@ static int gigaset_probe(struct usb_interface *interface,
 
        /* tell common part that the device is ready */
        if (startmode == SM_LOCKED)
-               atomic_set(&cs->mstate, MS_LOCKED);
+               cs->mstate = MS_LOCKED;
 
        if (!gigaset_start(cs)) {
                tasklet_kill(&cs->write_tasklet);
@@ -813,7 +816,7 @@ error:
        usb_put_dev(ucs->udev);
        ucs->udev = NULL;
        ucs->interface = NULL;
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
        return retval;
 }
 
@@ -824,6 +827,9 @@ static void gigaset_disconnect(struct usb_interface *interface)
 
        cs = usb_get_intfdata(interface);
        ucs = cs->hw.usb;
+
+       dev_info(cs->dev, "disconnecting Gigaset USB adapter\n");
+
        usb_kill_urb(ucs->read_urb);
 
        gigaset_stop(cs);
@@ -831,7 +837,7 @@ static void gigaset_disconnect(struct usb_interface *interface)
        usb_set_intfdata(interface, NULL);
        tasklet_kill(&cs->write_tasklet);
 
-       usb_kill_urb(ucs->bulk_out_urb);        /* FIXME: only if active? */
+       usb_kill_urb(ucs->bulk_out_urb);
 
        kfree(ucs->bulk_out_buffer);
        usb_free_urb(ucs->bulk_out_urb);
@@ -844,7 +850,53 @@ static void gigaset_disconnect(struct usb_interface *interface)
        ucs->interface = NULL;
        ucs->udev = NULL;
        cs->dev = NULL;
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
+}
+
+/* gigaset_suspend
+ * This function is called before the USB connection is suspended or reset.
+ */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+
+       /* stop activity */
+       cs->connected = 0;      /* prevent rescheduling */
+       usb_kill_urb(cs->hw.usb->read_urb);
+       tasklet_kill(&cs->write_tasklet);
+       usb_kill_urb(cs->hw.usb->bulk_out_urb);
+
+       gig_dbg(DEBUG_SUSPEND, "suspend complete");
+       return 0;
+}
+
+/* gigaset_resume
+ * This function is called after the USB connection has been resumed or reset.
+ */
+static int gigaset_resume(struct usb_interface *intf)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+       int rc;
+
+       /* resubmit interrupt URB */
+       cs->connected = 1;
+       rc = usb_submit_urb(cs->hw.usb->read_urb, GFP_KERNEL);
+       if (rc) {
+               dev_err(cs->dev, "Could not submit read URB (error %d)\n", -rc);
+               return rc;
+       }
+
+       gig_dbg(DEBUG_SUSPEND, "resume complete");
+       return 0;
+}
+
+/* gigaset_pre_reset
+ * This function is called before the USB connection is reset.
+ */
+static int gigaset_pre_reset(struct usb_interface *intf)
+{
+       /* same as suspend */
+       return gigaset_suspend(intf, PMSG_ON);
 }
 
 static const struct gigaset_ops ops = {
@@ -880,11 +932,6 @@ static int __init usb_gigaset_init(void)
                                       &ops, THIS_MODULE)) == NULL)
                goto error;
 
-       /* allocate memory for our device state and intialize it */
-       cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
-       if (!cardstate)
-               goto error;
-
        /* register this driver with the USB subsystem */
        result = usb_register(&gigaset_usb_driver);
        if (result < 0) {
@@ -897,9 +944,7 @@ static int __init usb_gigaset_init(void)
        info(DRIVER_DESC);
        return 0;
 
-error: if (cardstate)
-               gigaset_freecs(cardstate);
-       cardstate = NULL;
+error:
        if (driver)
                gigaset_freedriver(driver);
        driver = NULL;
@@ -913,11 +958,16 @@ error:    if (cardstate)
  */
 static void __exit usb_gigaset_exit(void)
 {
+       int i;
+
        gigaset_blockdriver(driver); /* => probe will fail
                                      * => no gigaset_start any more
                                      */
 
-       gigaset_shutdown(cardstate);
+       /* stop all connected devices */
+       for (i = 0; i < driver->minors; i++)
+               gigaset_shutdown(driver->cs + i);
+
        /* from now on, no isdn callback should be possible */
 
        /* deregister this driver with the USB subsystem */
@@ -925,8 +975,6 @@ static void __exit usb_gigaset_exit(void)
        /* this will call the disconnect-callback */
        /* from now on, no disconnect/probe callback should be running */
 
-       gigaset_freecs(cardstate);
-       cardstate = NULL;
        gigaset_freedriver(driver);
        driver = NULL;
 }
index 0db9cc661e28b7b224e49fd6a2cf34e191f92250..84318ec8d13eefc65d23e7b99764da500b395d88 100644 (file)
@@ -1188,7 +1188,7 @@ int SuperTraceASSIGN (void* AdapterHandle, byte* data) {
 
     if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) &&
         (features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) {
-      dword rx_dma_magic;
+      dword uninitialized_var(rx_dma_magic);
       if ((pC->dma_handle = diva_get_dma_descriptor (pC->request, &rx_dma_magic)) >= 0) {
         pC->xbuffer[0] = LLI;
         pC->xbuffer[1] = 8;
index ffa2afa77c2f199b8b2128d86d29597472f77694..1403a5458e68f9227af58ad9849177203befcc80 100644 (file)
@@ -515,12 +515,11 @@ diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
 
 irqreturn_t diva_os_irq_wrapper(int irq, void *context)
 {
-       diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
+       diva_os_xdi_adapter_t *a = context;
        diva_xdi_clear_interrupts_proc_t clear_int_proc;
 
-       if (!a || !a->xdi_adapter.diva_isr_handler) {
+       if (!a || !a->xdi_adapter.diva_isr_handler)
                return IRQ_NONE;
-       }
 
        if ((clear_int_proc = a->clear_interrupts_proc)) {
                (*clear_int_proc) (a);
index b9177ca4369a8d614eb8005335bacef00843fd0e..1ff98e7eb794cee276872c713672f1d5af951de6 100644 (file)
@@ -9027,7 +9027,7 @@ static byte AddInfo(byte   **add_i,
    /* facility is a nested structure */
    /* FTY can be more than once      */
 
-  if(esc_chi[0] && !(esc_chi[esc_chi[0]])&0x7f )
+       if (esc_chi[0] && !(esc_chi[esc_chi[0]] & 0x7f))
   {
     add_i[0] = (byte   *)"\x02\x02\x00"; /* use neither b nor d channel */
   }
index 035d158779df75f328eca89c77a3e968497fb0ba..0f1db1f669b28028162fcf205bb69c5bd4749359 100644 (file)
@@ -263,11 +263,7 @@ hdlc_empty_fifo(struct BCState *bcs, int count)
                outl(idx, cs->hw.avm.cfg_reg + 4);
                while (cnt < count) {
 #ifdef __powerpc__
-#ifdef CONFIG_APUS
-                       *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
-#else
                        *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
-#endif /* CONFIG_APUS */
 #else
                        *ptr++ = inl(cs->hw.avm.isac);
 #endif /* __powerpc__ */
@@ -328,11 +324,7 @@ hdlc_fill_fifo(struct BCState *bcs)
        if (cs->subtyp == AVM_FRITZ_PCI) {
                while (cnt<count) {
 #ifdef __powerpc__
-#ifdef CONFIG_APUS
-                       out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
-#else
                        out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
-#endif /* CONFIG_APUS */
 #else
                        outl(*ptr++, cs->hw.avm.isac);
 #endif /* __powerpc__ */
index 9cb6e5021adb93af85012396cf857b2fb82242f2..133eb18e65cca989dcd3f0755ae3d0f98f1c9a47 100644 (file)
@@ -1917,7 +1917,6 @@ isdn_tty_modem_init(void)
                info->owner = THIS_MODULE;
 #endif
                spin_lock_init(&info->readlock);
-               init_MUTEX(&info->write_sem);
                sprintf(info->last_cause, "0000");
                sprintf(info->last_num, "none");
                info->last_dir = 0;
index a943d078bacc2991bdd52e8680b4648c3aafb866..f93de4a303550afa4ea48b3ca6af7f7e4568a446 100644 (file)
@@ -834,7 +834,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
                char *rp = &f->resolution;
 
                p[0] += 2;
-               if (!info->faxonline & 1)       /* not outgoing connection */
+               if (!(info->faxonline & 1))     /* not outgoing connection */
                        PARSE_ERROR1;
 
                for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
index 82d957bde299453dcbd0b53173fc4e5efe18e5b2..bf7997abc4ac6da27bf972677ac3283e7e68d49c 100644 (file)
@@ -1302,7 +1302,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_DIAL:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (card->leased)
                                break;
@@ -1328,7 +1328,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_ACCEPTD:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ICN_BCH) {
                                a = c->arg + 1;
@@ -1348,7 +1348,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_ACCEPTB:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ICN_BCH) {
                                a = c->arg + 1;
@@ -1366,7 +1366,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_HANGUP:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ICN_BCH) {
                                a = c->arg + 1;
@@ -1375,7 +1375,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_SETEAZ:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (card->leased)
                                break;
@@ -1391,7 +1391,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_CLREAZ:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (card->leased)
                                break;
@@ -1405,7 +1405,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_SETL2:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if ((c->arg & 255) < ICN_BCH) {
                                a = c->arg;
@@ -1424,7 +1424,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_SETL3:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        return 0;
                default:
@@ -1471,7 +1471,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel)
        icn_card *card = icn_findcard(id);
 
        if (card) {
-               if (!card->flags & ICN_FLAGS_RUNNING)
+               if (!(card->flags & ICN_FLAGS_RUNNING))
                        return -ENODEV;
                return (icn_writecmd(buf, len, 1, card));
        }
@@ -1486,7 +1486,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel)
        icn_card *card = icn_findcard(id);
 
        if (card) {
-               if (!card->flags & ICN_FLAGS_RUNNING)
+               if (!(card->flags & ICN_FLAGS_RUNNING))
                        return -ENODEV;
                return (icn_readstatus(buf, len, card));
        }
@@ -1501,7 +1501,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
        icn_card *card = icn_findcard(id);
 
        if (card) {
-               if (!card->flags & ICN_FLAGS_RUNNING)
+               if (!(card->flags & ICN_FLAGS_RUNNING))
                        return -ENODEV;
                return (icn_sendbuf(channel, ack, skb, card));
        }
index bb92e3cd9334a0bdf2822d28ef47bf0739ef2303..655ef9a3f4df2a023d319967e9aa99dda93e4dc8 100644 (file)
@@ -1184,7 +1184,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                        }
                        break;
                case ISDN_CMD_DIAL:
-                       if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                return -ENODEV;
                        if (card->leased)
                                break;
@@ -1210,7 +1210,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                        }
                        break;
                case ISDN_CMD_ACCEPTD:
-                       if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ISDNLOOP_BCH) {
                                a = c->arg + 1;
@@ -1238,7 +1238,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                        }
                        break;
                case ISDN_CMD_ACCEPTB:
-                       if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ISDNLOOP_BCH) {
                                a = c->arg + 1;
@@ -1264,7 +1264,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                                i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
                                break;
                case ISDN_CMD_HANGUP:
-                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                        return -ENODEV;
                                if (c->arg < ISDNLOOP_BCH) {
                                        a = c->arg + 1;
@@ -1273,7 +1273,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                                }
                                break;
                case ISDN_CMD_SETEAZ:
-                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                        return -ENODEV;
                                if (card->leased)
                                        break;
@@ -1303,7 +1303,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                                }
                                break;
                case ISDN_CMD_SETL2:
-                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                        return -ENODEV;
                                if ((c->arg & 255) < ISDNLOOP_BCH) {
                                        a = c->arg;
@@ -1395,7 +1395,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel)
        isdnloop_card *card = isdnloop_findcard(id);
 
        if (card) {
-               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                        return -ENODEV;
                return (isdnloop_readstatus(buf, len, card));
        }
@@ -1410,7 +1410,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
        isdnloop_card *card = isdnloop_findcard(id);
 
        if (card) {
-               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                        return -ENODEV;
                /* ack request stored in skb scratch area */
                *(skb->head) = ack;
index 1b1ef3130e6e8cbbe32ea6d659882b92a408d59e..a0585fb6da94304758e7294f7b5288f0bbe1846f 100644 (file)
@@ -237,7 +237,7 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde
        if (!page)
                return ERR_PTR(-ENOMEM);
 
-       ITERATE_RDEV(mddev, rdev, tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (! test_bit(In_sync, &rdev->flags)
                    || test_bit(Faulty, &rdev->flags))
                        continue;
@@ -261,7 +261,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
        struct list_head *tmp;
        mddev_t *mddev = bitmap->mddev;
 
-       ITERATE_RDEV(mddev, rdev, tmp)
+       rdev_for_each(rdev, tmp, mddev)
                if (test_bit(In_sync, &rdev->flags)
                    && !test_bit(Faulty, &rdev->flags)) {
                        int size = PAGE_SIZE;
@@ -1348,14 +1348,38 @@ void bitmap_close_sync(struct bitmap *bitmap)
         */
        sector_t sector = 0;
        int blocks;
-       if (!bitmap) return;
+       if (!bitmap)
+               return;
        while (sector < bitmap->mddev->resync_max_sectors) {
                bitmap_end_sync(bitmap, sector, &blocks, 0);
-/*
-               if (sector < 500) printk("bitmap_close_sync: sec %llu blks %d\n",
-                                        (unsigned long long)sector, blocks);
-*/             sector += blocks;
+               sector += blocks;
+       }
+}
+
+void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector)
+{
+       sector_t s = 0;
+       int blocks;
+
+       if (!bitmap)
+               return;
+       if (sector == 0) {
+               bitmap->last_end_sync = jiffies;
+               return;
+       }
+       if (time_before(jiffies, (bitmap->last_end_sync
+                                 + bitmap->daemon_sleep * HZ)))
+               return;
+       wait_event(bitmap->mddev->recovery_wait,
+                  atomic_read(&bitmap->mddev->recovery_active) == 0);
+
+       sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1);
+       s = 0;
+       while (s < sector && s < bitmap->mddev->resync_max_sectors) {
+               bitmap_end_sync(bitmap, s, &blocks, 0);
+               s += blocks;
        }
+       bitmap->last_end_sync = jiffies;
 }
 
 static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed)
@@ -1565,3 +1589,4 @@ EXPORT_SYMBOL(bitmap_start_sync);
 EXPORT_SYMBOL(bitmap_end_sync);
 EXPORT_SYMBOL(bitmap_unplug);
 EXPORT_SYMBOL(bitmap_close_sync);
+EXPORT_SYMBOL(bitmap_cond_end_sync);
index cf2ddce341181cb19eb485afb1d1a5925128a57c..d107ddceefcd4651eabaca68f34cf608c4046a56 100644 (file)
@@ -294,7 +294,7 @@ static int run(mddev_t *mddev)
        }
        conf->nfaults = 0;
 
-       ITERATE_RDEV(mddev, rdev, tmp)
+       rdev_for_each(rdev, tmp, mddev)
                conf->rdev = rdev;
 
        mddev->array_size = mddev->size;
index 3dac1cfb81896655f953939a447bb731e9539747..0b8511776b3e75276e9a472ea759e0aa304fff48 100644 (file)
@@ -122,7 +122,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
        cnt = 0;
        conf->array_size = 0;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                int j = rdev->raid_disk;
                dev_info_t *disk = conf->disks + j;
 
index c28a120b4161ea7324eae5160ed2a4c2fc7e0ab6..5fc326d3970e511faf3e6f1a0b4fde30ac0f8f67 100644 (file)
@@ -195,7 +195,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
  * Any code which breaks out of this loop while own
  * a reference to the current mddev and must mddev_put it.
  */
-#define ITERATE_MDDEV(mddev,tmp)                                       \
+#define for_each_mddev(mddev,tmp)                                      \
                                                                        \
        for (({ spin_lock(&all_mddevs_lock);                            \
                tmp = all_mddevs.next;                                  \
@@ -275,6 +275,7 @@ static mddev_t * mddev_find(dev_t unit)
        spin_lock_init(&new->write_lock);
        init_waitqueue_head(&new->sb_wait);
        new->reshape_position = MaxSector;
+       new->resync_max = MaxSector;
 
        new->queue = blk_alloc_queue(GFP_KERNEL);
        if (!new->queue) {
@@ -310,7 +311,7 @@ static mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr)
        mdk_rdev_t * rdev;
        struct list_head *tmp;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (rdev->desc_nr == nr)
                        return rdev;
        }
@@ -322,7 +323,7 @@ static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev)
        struct list_head *tmp;
        mdk_rdev_t *rdev;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (rdev->bdev->bd_dev == dev)
                        return rdev;
        }
@@ -773,12 +774,16 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
        __u64 ev1 = md_event(sb);
 
        rdev->raid_disk = -1;
-       rdev->flags = 0;
+       clear_bit(Faulty, &rdev->flags);
+       clear_bit(In_sync, &rdev->flags);
+       clear_bit(WriteMostly, &rdev->flags);
+       clear_bit(BarriersNotsupp, &rdev->flags);
+
        if (mddev->raid_disks == 0) {
                mddev->major_version = 0;
                mddev->minor_version = sb->minor_version;
                mddev->patch_version = sb->patch_version;
-               mddev->persistent = ! sb->not_persistent;
+               mddev->external = 0;
                mddev->chunk_size = sb->chunk_size;
                mddev->ctime = sb->ctime;
                mddev->utime = sb->utime;
@@ -904,7 +909,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        sb->size  = mddev->size;
        sb->raid_disks = mddev->raid_disks;
        sb->md_minor = mddev->md_minor;
-       sb->not_persistent = !mddev->persistent;
+       sb->not_persistent = 0;
        sb->utime = mddev->utime;
        sb->state = 0;
        sb->events_hi = (mddev->events>>32);
@@ -938,7 +943,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
                sb->state |= (1<<MD_SB_BITMAP_PRESENT);
 
        sb->disks[0].state = (1<<MD_DISK_REMOVED);
-       ITERATE_RDEV(mddev,rdev2,tmp) {
+       rdev_for_each(rdev2, tmp, mddev) {
                mdp_disk_t *d;
                int desc_nr;
                if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
@@ -1153,11 +1158,15 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
        __u64 ev1 = le64_to_cpu(sb->events);
 
        rdev->raid_disk = -1;
-       rdev->flags = 0;
+       clear_bit(Faulty, &rdev->flags);
+       clear_bit(In_sync, &rdev->flags);
+       clear_bit(WriteMostly, &rdev->flags);
+       clear_bit(BarriersNotsupp, &rdev->flags);
+
        if (mddev->raid_disks == 0) {
                mddev->major_version = 1;
                mddev->patch_version = 0;
-               mddev->persistent = 1;
+               mddev->external = 0;
                mddev->chunk_size = le32_to_cpu(sb->chunksize) << 9;
                mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1);
                mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1);
@@ -1286,7 +1295,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        }
 
        max_dev = 0;
-       ITERATE_RDEV(mddev,rdev2,tmp)
+       rdev_for_each(rdev2, tmp, mddev)
                if (rdev2->desc_nr+1 > max_dev)
                        max_dev = rdev2->desc_nr+1;
 
@@ -1295,7 +1304,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        for (i=0; i<max_dev;i++)
                sb->dev_roles[i] = cpu_to_le16(0xfffe);
        
-       ITERATE_RDEV(mddev,rdev2,tmp) {
+       rdev_for_each(rdev2, tmp, mddev) {
                i = rdev2->desc_nr;
                if (test_bit(Faulty, &rdev2->flags))
                        sb->dev_roles[i] = cpu_to_le16(0xfffe);
@@ -1333,8 +1342,8 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
        struct list_head *tmp, *tmp2;
        mdk_rdev_t *rdev, *rdev2;
 
-       ITERATE_RDEV(mddev1,rdev,tmp)
-               ITERATE_RDEV(mddev2, rdev2, tmp2)
+       rdev_for_each(rdev, tmp, mddev1)
+               rdev_for_each(rdev2, tmp2, mddev2)
                        if (rdev->bdev->bd_contains ==
                            rdev2->bdev->bd_contains)
                                return 1;
@@ -1401,7 +1410,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
                goto fail;
        }
        list_add(&rdev->same_set, &mddev->disks);
-       bd_claim_by_disk(rdev->bdev, rdev, mddev->gendisk);
+       bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
        return 0;
 
  fail:
@@ -1410,10 +1419,11 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
        return err;
 }
 
-static void delayed_delete(struct work_struct *ws)
+static void md_delayed_delete(struct work_struct *ws)
 {
        mdk_rdev_t *rdev = container_of(ws, mdk_rdev_t, del_work);
        kobject_del(&rdev->kobj);
+       kobject_put(&rdev->kobj);
 }
 
 static void unbind_rdev_from_array(mdk_rdev_t * rdev)
@@ -1432,7 +1442,8 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
        /* We need to delay this, otherwise we can deadlock when
         * writing to 'remove' to "dev/state"
         */
-       INIT_WORK(&rdev->del_work, delayed_delete);
+       INIT_WORK(&rdev->del_work, md_delayed_delete);
+       kobject_get(&rdev->kobj);
        schedule_work(&rdev->del_work);
 }
 
@@ -1441,7 +1452,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
  * otherwise reused by a RAID array (or any other kernel
  * subsystem), by bd_claiming the device.
  */
-static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
+static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared)
 {
        int err = 0;
        struct block_device *bdev;
@@ -1453,13 +1464,15 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
                        __bdevname(dev, b));
                return PTR_ERR(bdev);
        }
-       err = bd_claim(bdev, rdev);
+       err = bd_claim(bdev, shared ? (mdk_rdev_t *)lock_rdev : rdev);
        if (err) {
                printk(KERN_ERR "md: could not bd_claim %s.\n",
                        bdevname(bdev, b));
                blkdev_put(bdev);
                return err;
        }
+       if (!shared)
+               set_bit(AllReserved, &rdev->flags);
        rdev->bdev = bdev;
        return err;
 }
@@ -1503,7 +1516,7 @@ static void export_array(mddev_t *mddev)
        struct list_head *tmp;
        mdk_rdev_t *rdev;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (!rdev->mddev) {
                        MD_BUG();
                        continue;
@@ -1581,17 +1594,17 @@ static void md_print_devices(void)
        printk("md:     **********************************\n");
        printk("md:     * <COMPLETE RAID STATE PRINTOUT> *\n");
        printk("md:     **********************************\n");
-       ITERATE_MDDEV(mddev,tmp) {
+       for_each_mddev(mddev, tmp) {
 
                if (mddev->bitmap)
                        bitmap_print_sb(mddev->bitmap);
                else
                        printk("%s: ", mdname(mddev));
-               ITERATE_RDEV(mddev,rdev,tmp2)
+               rdev_for_each(rdev, tmp2, mddev)
                        printk("<%s>", bdevname(rdev->bdev,b));
                printk("\n");
 
-               ITERATE_RDEV(mddev,rdev,tmp2)
+               rdev_for_each(rdev, tmp2, mddev)
                        print_rdev(rdev);
        }
        printk("md:     **********************************\n");
@@ -1610,7 +1623,7 @@ static void sync_sbs(mddev_t * mddev, int nospares)
        mdk_rdev_t *rdev;
        struct list_head *tmp;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (rdev->sb_events == mddev->events ||
                    (nospares &&
                     rdev->raid_disk < 0 &&
@@ -1696,18 +1709,20 @@ repeat:
                MD_BUG();
                mddev->events --;
        }
-       sync_sbs(mddev, nospares);
 
        /*
         * do not write anything to disk if using
         * nonpersistent superblocks
         */
        if (!mddev->persistent) {
-               clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+               if (!mddev->external)
+                       clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+
                spin_unlock_irq(&mddev->write_lock);
                wake_up(&mddev->sb_wait);
                return;
        }
+       sync_sbs(mddev, nospares);
        spin_unlock_irq(&mddev->write_lock);
 
        dprintk(KERN_INFO 
@@ -1715,7 +1730,7 @@ repeat:
                mdname(mddev),mddev->in_sync);
 
        bitmap_update_sb(mddev->bitmap);
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                char b[BDEVNAME_SIZE];
                dprintk(KERN_INFO "md: ");
                if (rdev->sb_loaded != 1)
@@ -1785,7 +1800,7 @@ static ssize_t
 state_show(mdk_rdev_t *rdev, char *page)
 {
        char *sep = "";
-       int len=0;
+       size_t len = 0;
 
        if (test_bit(Faulty, &rdev->flags)) {
                len+= sprintf(page+len, "%sfaulty",sep);
@@ -1887,20 +1902,45 @@ static ssize_t
 slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 {
        char *e;
+       int err;
+       char nm[20];
        int slot = simple_strtoul(buf, &e, 10);
        if (strncmp(buf, "none", 4)==0)
                slot = -1;
        else if (e==buf || (*e && *e!= '\n'))
                return -EINVAL;
-       if (rdev->mddev->pers)
-               /* Cannot set slot in active array (yet) */
-               return -EBUSY;
-       if (slot >= rdev->mddev->raid_disks)
-               return -ENOSPC;
-       rdev->raid_disk = slot;
-       /* assume it is working */
-       rdev->flags = 0;
-       set_bit(In_sync, &rdev->flags);
+       if (rdev->mddev->pers) {
+               /* Setting 'slot' on an active array requires also
+                * updating the 'rd%d' link, and communicating
+                * with the personality with ->hot_*_disk.
+                * For now we only support removing
+                * failed/spare devices.  This normally happens automatically,
+                * but not when the metadata is externally managed.
+                */
+               if (slot != -1)
+                       return -EBUSY;
+               if (rdev->raid_disk == -1)
+                       return -EEXIST;
+               /* personality does all needed checks */
+               if (rdev->mddev->pers->hot_add_disk == NULL)
+                       return -EINVAL;
+               err = rdev->mddev->pers->
+                       hot_remove_disk(rdev->mddev, rdev->raid_disk);
+               if (err)
+                       return err;
+               sprintf(nm, "rd%d", rdev->raid_disk);
+               sysfs_remove_link(&rdev->mddev->kobj, nm);
+               set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
+               md_wakeup_thread(rdev->mddev->thread);
+       } else {
+               if (slot >= rdev->mddev->raid_disks)
+                       return -ENOSPC;
+               rdev->raid_disk = slot;
+               /* assume it is working */
+               clear_bit(Faulty, &rdev->flags);
+               clear_bit(WriteMostly, &rdev->flags);
+               set_bit(In_sync, &rdev->flags);
+       }
        return len;
 }
 
@@ -1923,6 +1963,10 @@ offset_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                return -EINVAL;
        if (rdev->mddev->pers)
                return -EBUSY;
+       if (rdev->size && rdev->mddev->external)
+               /* Must set offset before size, so overlap checks
+                * can be sane */
+               return -EBUSY;
        rdev->data_offset = offset;
        return len;
 }
@@ -1936,16 +1980,69 @@ rdev_size_show(mdk_rdev_t *rdev, char *page)
        return sprintf(page, "%llu\n", (unsigned long long)rdev->size);
 }
 
+static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2)
+{
+       /* check if two start/length pairs overlap */
+       if (s1+l1 <= s2)
+               return 0;
+       if (s2+l2 <= s1)
+               return 0;
+       return 1;
+}
+
 static ssize_t
 rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 {
        char *e;
        unsigned long long size = simple_strtoull(buf, &e, 10);
+       unsigned long long oldsize = rdev->size;
        if (e==buf || (*e && *e != '\n'))
                return -EINVAL;
        if (rdev->mddev->pers)
                return -EBUSY;
        rdev->size = size;
+       if (size > oldsize && rdev->mddev->external) {
+               /* need to check that all other rdevs with the same ->bdev
+                * do not overlap.  We need to unlock the mddev to avoid
+                * a deadlock.  We have already changed rdev->size, and if
+                * we have to change it back, we will have the lock again.
+                */
+               mddev_t *mddev;
+               int overlap = 0;
+               struct list_head *tmp, *tmp2;
+
+               mddev_unlock(rdev->mddev);
+               for_each_mddev(mddev, tmp) {
+                       mdk_rdev_t *rdev2;
+
+                       mddev_lock(mddev);
+                       rdev_for_each(rdev2, tmp2, mddev)
+                               if (test_bit(AllReserved, &rdev2->flags) ||
+                                   (rdev->bdev == rdev2->bdev &&
+                                    rdev != rdev2 &&
+                                    overlaps(rdev->data_offset, rdev->size,
+                                           rdev2->data_offset, rdev2->size))) {
+                                       overlap = 1;
+                                       break;
+                               }
+                       mddev_unlock(mddev);
+                       if (overlap) {
+                               mddev_put(mddev);
+                               break;
+                       }
+               }
+               mddev_lock(rdev->mddev);
+               if (overlap) {
+                       /* Someone else could have slipped in a size
+                        * change here, but doing so is just silly.
+                        * We put oldsize back because we *know* it is
+                        * safe, and trust userspace not to race with
+                        * itself
+                        */
+                       rdev->size = oldsize;
+                       return -EBUSY;
+               }
+       }
        if (size < rdev->mddev->size || rdev->mddev->size == 0)
                rdev->mddev->size = size;
        return len;
@@ -1980,12 +2077,18 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr,
 {
        struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
        mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+       int rv;
 
        if (!entry->store)
                return -EIO;
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
-       return entry->store(rdev, page, length);
+       rv = mddev_lock(rdev->mddev);
+       if (!rv) {
+               rv = entry->store(rdev, page, length);
+               mddev_unlock(rdev->mddev);
+       }
+       return rv;
 }
 
 static void rdev_free(struct kobject *ko)
@@ -2029,7 +2132,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
        if ((err = alloc_disk_sb(rdev)))
                goto abort_free;
 
-       err = lock_rdev(rdev, newdev);
+       err = lock_rdev(rdev, newdev, super_format == -2);
        if (err)
                goto abort_free;
 
@@ -2099,7 +2202,7 @@ static void analyze_sbs(mddev_t * mddev)
        char b[BDEVNAME_SIZE];
 
        freshest = NULL;
-       ITERATE_RDEV(mddev,rdev,tmp)
+       rdev_for_each(rdev, tmp, mddev)
                switch (super_types[mddev->major_version].
                        load_super(rdev, freshest, mddev->minor_version)) {
                case 1:
@@ -2120,7 +2223,7 @@ static void analyze_sbs(mddev_t * mddev)
                validate_super(mddev, freshest);
 
        i = 0;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (rdev != freshest)
                        if (super_types[mddev->major_version].
                            validate_super(mddev, rdev)) {
@@ -2215,7 +2318,7 @@ level_show(mddev_t *mddev, char *page)
 static ssize_t
 level_store(mddev_t *mddev, const char *buf, size_t len)
 {
-       int rv = len;
+       ssize_t rv = len;
        if (mddev->pers)
                return -EBUSY;
        if (len == 0)
@@ -2425,6 +2528,8 @@ array_state_show(mddev_t *mddev, char *page)
                case 0:
                        if (mddev->in_sync)
                                st = clean;
+                       else if (test_bit(MD_CHANGE_CLEAN, &mddev->flags))
+                               st = write_pending;
                        else if (mddev->safemode)
                                st = active_idle;
                        else
@@ -2455,11 +2560,9 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
                break;
        case clear:
                /* stopping an active array */
-               if (mddev->pers) {
-                       if (atomic_read(&mddev->active) > 1)
-                               return -EBUSY;
-                       err = do_md_stop(mddev, 0);
-               }
+               if (atomic_read(&mddev->active) > 1)
+                       return -EBUSY;
+               err = do_md_stop(mddev, 0);
                break;
        case inactive:
                /* stopping an active array */
@@ -2467,7 +2570,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
                        if (atomic_read(&mddev->active) > 1)
                                return -EBUSY;
                        err = do_md_stop(mddev, 2);
-               }
+               } else
+                       err = 0; /* already inactive */
                break;
        case suspended:
                break; /* not supported yet */
@@ -2495,9 +2599,15 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
                        restart_array(mddev);
                        spin_lock_irq(&mddev->write_lock);
                        if (atomic_read(&mddev->writes_pending) == 0) {
-                               mddev->in_sync = 1;
-                               set_bit(MD_CHANGE_CLEAN, &mddev->flags);
-                       }
+                               if (mddev->in_sync == 0) {
+                                       mddev->in_sync = 1;
+                                       if (mddev->persistent)
+                                               set_bit(MD_CHANGE_CLEAN,
+                                                       &mddev->flags);
+                               }
+                               err = 0;
+                       } else
+                               err = -EBUSY;
                        spin_unlock_irq(&mddev->write_lock);
                } else {
                        mddev->ro = 0;
@@ -2508,7 +2618,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
        case active:
                if (mddev->pers) {
                        restart_array(mddev);
-                       clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
+                       if (mddev->external)
+                               clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
                        wake_up(&mddev->sb_wait);
                        err = 0;
                } else {
@@ -2574,7 +2685,9 @@ new_dev_store(mddev_t *mddev, const char *buf, size_t len)
                        if (err < 0)
                                goto out;
                }
-       } else
+       } else if (mddev->external)
+               rdev = md_import_device(dev, -2, -1);
+       else
                rdev = md_import_device(dev, -1, -1);
 
        if (IS_ERR(rdev))
@@ -2659,7 +2772,9 @@ __ATTR(component_size, S_IRUGO|S_IWUSR, size_show, size_store);
 
 
 /* Metdata version.
- * This is either 'none' for arrays with externally managed metadata,
+ * This is one of
+ *   'none' for arrays with no metadata (good luck...)
+ *   'external' for arrays with externally managed metadata,
  * or N.M for internally known formats
  */
 static ssize_t
@@ -2668,6 +2783,8 @@ metadata_show(mddev_t *mddev, char *page)
        if (mddev->persistent)
                return sprintf(page, "%d.%d\n",
                               mddev->major_version, mddev->minor_version);
+       else if (mddev->external)
+               return sprintf(page, "external:%s\n", mddev->metadata_type);
        else
                return sprintf(page, "none\n");
 }
@@ -2682,6 +2799,21 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
 
        if (cmd_match(buf, "none")) {
                mddev->persistent = 0;
+               mddev->external = 0;
+               mddev->major_version = 0;
+               mddev->minor_version = 90;
+               return len;
+       }
+       if (strncmp(buf, "external:", 9) == 0) {
+               size_t namelen = len-9;
+               if (namelen >= sizeof(mddev->metadata_type))
+                       namelen = sizeof(mddev->metadata_type)-1;
+               strncpy(mddev->metadata_type, buf+9, namelen);
+               mddev->metadata_type[namelen] = 0;
+               if (namelen && mddev->metadata_type[namelen-1] == '\n')
+                       mddev->metadata_type[--namelen] = 0;
+               mddev->persistent = 0;
+               mddev->external = 1;
                mddev->major_version = 0;
                mddev->minor_version = 90;
                return len;
@@ -2698,6 +2830,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
        mddev->major_version = major;
        mddev->minor_version = minor;
        mddev->persistent = 1;
+       mddev->external = 0;
        return len;
 }
 
@@ -2864,6 +2997,43 @@ sync_completed_show(mddev_t *mddev, char *page)
 
 static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
 
+static ssize_t
+max_sync_show(mddev_t *mddev, char *page)
+{
+       if (mddev->resync_max == MaxSector)
+               return sprintf(page, "max\n");
+       else
+               return sprintf(page, "%llu\n",
+                              (unsigned long long)mddev->resync_max);
+}
+static ssize_t
+max_sync_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       if (strncmp(buf, "max", 3) == 0)
+               mddev->resync_max = MaxSector;
+       else {
+               char *ep;
+               unsigned long long max = simple_strtoull(buf, &ep, 10);
+               if (ep == buf || (*ep != 0 && *ep != '\n'))
+                       return -EINVAL;
+               if (max < mddev->resync_max &&
+                   test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+                       return -EBUSY;
+
+               /* Must be a multiple of chunk_size */
+               if (mddev->chunk_size) {
+                       if (max & (sector_t)((mddev->chunk_size>>9)-1))
+                               return -EINVAL;
+               }
+               mddev->resync_max = max;
+       }
+       wake_up(&mddev->recovery_wait);
+       return len;
+}
+
+static struct md_sysfs_entry md_max_sync =
+__ATTR(sync_max, S_IRUGO|S_IWUSR, max_sync_show, max_sync_store);
+
 static ssize_t
 suspend_lo_show(mddev_t *mddev, char *page)
 {
@@ -2974,6 +3144,7 @@ static struct attribute *md_redundancy_attrs[] = {
        &md_sync_max.attr,
        &md_sync_speed.attr,
        &md_sync_completed.attr,
+       &md_max_sync.attr,
        &md_suspend_lo.attr,
        &md_suspend_hi.attr,
        &md_bitmap.attr,
@@ -3118,8 +3289,11 @@ static int do_md_run(mddev_t * mddev)
        /*
         * Analyze all RAID superblock(s)
         */
-       if (!mddev->raid_disks)
+       if (!mddev->raid_disks) {
+               if (!mddev->persistent)
+                       return -EINVAL;
                analyze_sbs(mddev);
+       }
 
        chunk_size = mddev->chunk_size;
 
@@ -3143,7 +3317,7 @@ static int do_md_run(mddev_t * mddev)
                }
 
                /* devices must have minimum size of one chunk */
-               ITERATE_RDEV(mddev,rdev,tmp) {
+               rdev_for_each(rdev, tmp, mddev) {
                        if (test_bit(Faulty, &rdev->flags))
                                continue;
                        if (rdev->size < chunk_size / 1024) {
@@ -3170,7 +3344,7 @@ static int do_md_run(mddev_t * mddev)
         * the only valid external interface is through the md
         * device.
         */
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (test_bit(Faulty, &rdev->flags))
                        continue;
                sync_blockdev(rdev->bdev);
@@ -3236,8 +3410,8 @@ static int do_md_run(mddev_t * mddev)
                mdk_rdev_t *rdev2;
                struct list_head *tmp2;
                int warned = 0;
-               ITERATE_RDEV(mddev, rdev, tmp) {
-                       ITERATE_RDEV(mddev, rdev2, tmp2) {
+               rdev_for_each(rdev, tmp, mddev) {
+                       rdev_for_each(rdev2, tmp2, mddev) {
                                if (rdev < rdev2 &&
                                    rdev->bdev->bd_contains ==
                                    rdev2->bdev->bd_contains) {
@@ -3297,7 +3471,7 @@ static int do_md_run(mddev_t * mddev)
        mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
        mddev->in_sync = 1;
 
-       ITERATE_RDEV(mddev,rdev,tmp)
+       rdev_for_each(rdev, tmp, mddev)
                if (rdev->raid_disk >= 0) {
                        char nm[20];
                        sprintf(nm, "rd%d", rdev->raid_disk);
@@ -3330,7 +3504,7 @@ static int do_md_run(mddev_t * mddev)
        if (mddev->degraded && !mddev->sync_thread) {
                struct list_head *rtmp;
                int spares = 0;
-               ITERATE_RDEV(mddev,rdev,rtmp)
+               rdev_for_each(rdev, rtmp, mddev)
                        if (rdev->raid_disk >= 0 &&
                            !test_bit(In_sync, &rdev->flags) &&
                            !test_bit(Faulty, &rdev->flags))
@@ -3507,14 +3681,14 @@ static int do_md_stop(mddev_t * mddev, int mode)
                }
                mddev->bitmap_offset = 0;
 
-               ITERATE_RDEV(mddev,rdev,tmp)
+               rdev_for_each(rdev, tmp, mddev)
                        if (rdev->raid_disk >= 0) {
                                char nm[20];
                                sprintf(nm, "rd%d", rdev->raid_disk);
                                sysfs_remove_link(&mddev->kobj, nm);
                        }
 
-               /* make sure all delayed_delete calls have finished */
+               /* make sure all md_delayed_delete calls have finished */
                flush_scheduled_work();
 
                export_array(mddev);
@@ -3523,7 +3697,10 @@ static int do_md_stop(mddev_t * mddev, int mode)
                mddev->size = 0;
                mddev->raid_disks = 0;
                mddev->recovery_cp = 0;
+               mddev->resync_max = MaxSector;
                mddev->reshape_position = MaxSector;
+               mddev->external = 0;
+               mddev->persistent = 0;
 
        } else if (mddev->pers)
                printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -3546,7 +3723,7 @@ static void autorun_array(mddev_t *mddev)
 
        printk(KERN_INFO "md: running: ");
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                char b[BDEVNAME_SIZE];
                printk("<%s>", bdevname(rdev->bdev,b));
        }
@@ -3589,7 +3766,7 @@ static void autorun_devices(int part)
                printk(KERN_INFO "md: considering %s ...\n",
                        bdevname(rdev0->bdev,b));
                INIT_LIST_HEAD(&candidates);
-               ITERATE_RDEV_PENDING(rdev,tmp)
+               rdev_for_each_list(rdev, tmp, pending_raid_disks)
                        if (super_90_load(rdev, rdev0, 0) >= 0) {
                                printk(KERN_INFO "md:  adding %s ...\n",
                                        bdevname(rdev->bdev,b));
@@ -3632,7 +3809,8 @@ static void autorun_devices(int part)
                        mddev_unlock(mddev);
                } else {
                        printk(KERN_INFO "md: created %s\n", mdname(mddev));
-                       ITERATE_RDEV_GENERIC(candidates,rdev,tmp) {
+                       mddev->persistent = 1;
+                       rdev_for_each_list(rdev, tmp, candidates) {
                                list_del_init(&rdev->same_set);
                                if (bind_rdev_to_array(rdev, mddev))
                                        export_rdev(rdev);
@@ -3643,7 +3821,7 @@ static void autorun_devices(int part)
                /* on success, candidates will be empty, on error
                 * it won't...
                 */
-               ITERATE_RDEV_GENERIC(candidates,rdev,tmp)
+               rdev_for_each_list(rdev, tmp, candidates)
                        export_rdev(rdev);
                mddev_put(mddev);
        }
@@ -3673,7 +3851,7 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
        struct list_head *tmp;
 
        nr=working=active=failed=spare=0;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                nr++;
                if (test_bit(Faulty, &rdev->flags))
                        failed++;
@@ -3919,8 +4097,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                else
                        rdev->raid_disk = -1;
 
-               rdev->flags = 0;
-
                if (rdev->raid_disk < mddev->raid_disks)
                        if (info->state & (1<<MD_DISK_SYNC))
                                set_bit(In_sync, &rdev->flags);
@@ -4165,13 +4341,15 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
        else
                mddev->recovery_cp = 0;
        mddev->persistent    = ! info->not_persistent;
+       mddev->external      = 0;
 
        mddev->layout        = info->layout;
        mddev->chunk_size    = info->chunk_size;
 
        mddev->max_disks     = MD_SB_DISKS;
 
-       mddev->flags         = 0;
+       if (mddev->persistent)
+               mddev->flags         = 0;
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
 
        mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
@@ -4213,7 +4391,7 @@ static int update_size(mddev_t *mddev, unsigned long size)
         */
        if (mddev->sync_thread)
                return -EBUSY;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                sector_t avail;
                avail = rdev->size * 2;
 
@@ -4471,9 +4649,10 @@ static int md_ioctl(struct inode *inode, struct file *file,
         */
        /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
         * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
-       if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
-                       && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
-                       && cmd != GET_BITMAP_FILE) {
+       if ((!mddev->raid_disks && !mddev->external)
+           && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
+           && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
+           && cmd != GET_BITMAP_FILE) {
                err = -ENODEV;
                goto abort_unlock;
        }
@@ -4757,7 +4936,7 @@ static void status_unused(struct seq_file *seq)
 
        seq_printf(seq, "unused devices: ");
 
-       ITERATE_RDEV_PENDING(rdev,tmp) {
+       rdev_for_each_list(rdev, tmp, pending_raid_disks) {
                char b[BDEVNAME_SIZE];
                i++;
                seq_printf(seq, "%s ",
@@ -4953,7 +5132,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
                }
 
                size = 0;
-               ITERATE_RDEV(mddev,rdev,tmp2) {
+               rdev_for_each(rdev, tmp2, mddev) {
                        char b[BDEVNAME_SIZE];
                        seq_printf(seq, " %s[%d]",
                                bdevname(rdev->bdev,b), rdev->desc_nr);
@@ -4982,7 +5161,10 @@ static int md_seq_show(struct seq_file *seq, void *v)
                                           mddev->major_version,
                                           mddev->minor_version);
                        }
-               } else
+               } else if (mddev->external)
+                       seq_printf(seq, " super external:%s",
+                                  mddev->metadata_type);
+               else
                        seq_printf(seq, " super non-persistent");
 
                if (mddev->pers) {
@@ -5106,7 +5288,7 @@ static int is_mddev_idle(mddev_t *mddev)
        long curr_events;
 
        idle = 1;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
                curr_events = disk_stat_read(disk, sectors[0]) + 
                                disk_stat_read(disk, sectors[1]) - 
@@ -5283,7 +5465,7 @@ void md_do_sync(mddev_t *mddev)
                        set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                        goto skip;
                }
-               ITERATE_MDDEV(mddev2,tmp) {
+               for_each_mddev(mddev2, tmp) {
                        if (mddev2 == mddev)
                                continue;
                        if (mddev2->curr_resync && 
@@ -5333,7 +5515,7 @@ void md_do_sync(mddev_t *mddev)
                /* recovery follows the physical size of devices */
                max_sectors = mddev->size << 1;
                j = MaxSector;
-               ITERATE_RDEV(mddev,rdev,rtmp)
+               rdev_for_each(rdev, rtmp, mddev)
                        if (rdev->raid_disk >= 0 &&
                            !test_bit(Faulty, &rdev->flags) &&
                            !test_bit(In_sync, &rdev->flags) &&
@@ -5381,8 +5563,16 @@ void md_do_sync(mddev_t *mddev)
                sector_t sectors;
 
                skipped = 0;
+               if (j >= mddev->resync_max) {
+                       sysfs_notify(&mddev->kobj, NULL, "sync_completed");
+                       wait_event(mddev->recovery_wait,
+                                  mddev->resync_max > j
+                                  || kthread_should_stop());
+               }
+               if (kthread_should_stop())
+                       goto interrupted;
                sectors = mddev->pers->sync_request(mddev, j, &skipped,
-                                           currspeed < speed_min(mddev));
+                                                 currspeed < speed_min(mddev));
                if (sectors == 0) {
                        set_bit(MD_RECOVERY_ERR, &mddev->recovery);
                        goto out;
@@ -5424,15 +5614,9 @@ void md_do_sync(mddev_t *mddev)
                }
 
 
-               if (kthread_should_stop()) {
-                       /*
-                        * got a signal, exit.
-                        */
-                       printk(KERN_INFO 
-                               "md: md_do_sync() got signal ... exiting\n");
-                       set_bit(MD_RECOVERY_INTR, &mddev->recovery);
-                       goto out;
-               }
+               if (kthread_should_stop())
+                       goto interrupted;
+
 
                /*
                 * this loop exits only if either when we are slower than
@@ -5484,7 +5668,7 @@ void md_do_sync(mddev_t *mddev)
                } else {
                        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
                                mddev->curr_resync = MaxSector;
-                       ITERATE_RDEV(mddev,rdev,rtmp)
+                       rdev_for_each(rdev, rtmp, mddev)
                                if (rdev->raid_disk >= 0 &&
                                    !test_bit(Faulty, &rdev->flags) &&
                                    !test_bit(In_sync, &rdev->flags) &&
@@ -5496,9 +5680,22 @@ void md_do_sync(mddev_t *mddev)
 
  skip:
        mddev->curr_resync = 0;
+       mddev->resync_max = MaxSector;
+       sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        wake_up(&resync_wait);
        set_bit(MD_RECOVERY_DONE, &mddev->recovery);
        md_wakeup_thread(mddev->thread);
+       return;
+
+ interrupted:
+       /*
+        * got a signal, exit.
+        */
+       printk(KERN_INFO
+              "md: md_do_sync() got signal ... exiting\n");
+       set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+       goto out;
+
 }
 EXPORT_SYMBOL_GPL(md_do_sync);
 
@@ -5509,8 +5706,9 @@ static int remove_and_add_spares(mddev_t *mddev)
        struct list_head *rtmp;
        int spares = 0;
 
-       ITERATE_RDEV(mddev,rdev,rtmp)
+       rdev_for_each(rdev, rtmp, mddev)
                if (rdev->raid_disk >= 0 &&
+                   !mddev->external &&
                    (test_bit(Faulty, &rdev->flags) ||
                     ! test_bit(In_sync, &rdev->flags)) &&
                    atomic_read(&rdev->nr_pending)==0) {
@@ -5524,7 +5722,7 @@ static int remove_and_add_spares(mddev_t *mddev)
                }
 
        if (mddev->degraded) {
-               ITERATE_RDEV(mddev,rdev,rtmp)
+               rdev_for_each(rdev, rtmp, mddev)
                        if (rdev->raid_disk < 0
                            && !test_bit(Faulty, &rdev->flags)) {
                                rdev->recovery_offset = 0;
@@ -5589,7 +5787,7 @@ void md_check_recovery(mddev_t *mddev)
        }
 
        if ( ! (
-               mddev->flags ||
+               (mddev->flags && !mddev->external) ||
                test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
                test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
                (mddev->safemode == 1) ||
@@ -5605,7 +5803,8 @@ void md_check_recovery(mddev_t *mddev)
                if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
                    !mddev->in_sync && mddev->recovery_cp == MaxSector) {
                        mddev->in_sync = 1;
-                       set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+                       if (mddev->persistent)
+                               set_bit(MD_CHANGE_CLEAN, &mddev->flags);
                }
                if (mddev->safemode == 1)
                        mddev->safemode = 0;
@@ -5637,7 +5836,7 @@ void md_check_recovery(mddev_t *mddev)
                         * information must be scrapped
                         */
                        if (!mddev->degraded)
-                               ITERATE_RDEV(mddev,rdev,rtmp)
+                               rdev_for_each(rdev, rtmp, mddev)
                                        rdev->saved_raid_disk = -1;
 
                        mddev->recovery = 0;
@@ -5714,7 +5913,7 @@ static int md_notify_reboot(struct notifier_block *this,
 
                printk(KERN_INFO "md: stopping all md devices.\n");
 
-               ITERATE_MDDEV(mddev,tmp)
+               for_each_mddev(mddev, tmp)
                        if (mddev_trylock(mddev)) {
                                do_md_stop (mddev, 1);
                                mddev_unlock(mddev);
@@ -5848,7 +6047,7 @@ static __exit void md_exit(void)
        unregister_reboot_notifier(&md_notifier);
        unregister_sysctl_table(raid_table_header);
        remove_proc_entry("mdstat", NULL);
-       ITERATE_MDDEV(mddev,tmp) {
+       for_each_mddev(mddev, tmp) {
                struct gendisk *disk = mddev->gendisk;
                if (!disk)
                        continue;
index adef299908cf79b8323de234882730fc4a82b220..b61d5767aae7c61c3960a09e16c26becb3a1712f 100644 (file)
@@ -1,13 +1,10 @@
-#ident "$Id: mktables.c,v 1.2 2002/12/12 22:41:27 hpa Exp $"
-/* ----------------------------------------------------------------------- *
+/* -*- linux-c -*- ------------------------------------------------------- *
  *
- *   Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2002-2007 H. Peter Anvin - 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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
- *   (at your option) any later version; incorporated herein by reference.
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2 or (at your
+ *   option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
 
 
 static uint8_t gfmul(uint8_t a, uint8_t b)
 {
-  uint8_t v = 0;
-
-  while ( b ) {
-    if ( b & 1 ) v ^= a;
-    a = (a << 1) ^ (a & 0x80 ? 0x1d : 0);
-    b >>= 1;
-  }
-  return v;
+       uint8_t v = 0;
+
+       while (b) {
+               if (b & 1)
+                       v ^= a;
+               a = (a << 1) ^ (a & 0x80 ? 0x1d : 0);
+               b >>= 1;
+       }
+
+       return v;
 }
 
 static uint8_t gfpow(uint8_t a, int b)
 {
-  uint8_t v = 1;
-
-  b %= 255;
-  if ( b < 0 )
-    b += 255;
-
-  while ( b ) {
-    if ( b & 1 ) v = gfmul(v,a);
-    a = gfmul(a,a);
-    b >>= 1;
-  }
-  return v;
+       uint8_t v = 1;
+
+       b %= 255;
+       if (b < 0)
+               b += 255;
+
+       while (b) {
+               if (b & 1)
+                       v = gfmul(v, a);
+               a = gfmul(a, a);
+               b >>= 1;
+       }
+
+       return v;
 }
 
 int main(int argc, char *argv[])
 {
-  int i, j, k;
-  uint8_t v;
-  uint8_t exptbl[256], invtbl[256];
-
-  printf("#include \"raid6.h\"\n");
-
-  /* Compute multiplication table */
-  printf("\nconst u8  __attribute__((aligned(256)))\n"
-        "raid6_gfmul[256][256] =\n"
-        "{\n");
-  for ( i = 0 ; i < 256 ; i++ ) {
-    printf("\t{\n");
-    for ( j = 0 ; j < 256 ; j += 8 ) {
-      printf("\t\t");
-      for ( k = 0 ; k < 8 ; k++ ) {
-       printf("0x%02x, ", gfmul(i,j+k));
-      }
-      printf("\n");
-    }
-    printf("\t},\n");
-  }
-  printf("};\n");
-
-  /* Compute power-of-2 table (exponent) */
-  v = 1;
-  printf("\nconst u8 __attribute__((aligned(256)))\n"
-        "raid6_gfexp[256] =\n"
-        "{\n");
-  for ( i = 0 ; i < 256 ; i += 8 ) {
-    printf("\t");
-    for ( j = 0 ; j < 8 ; j++ ) {
-      exptbl[i+j] = v;
-      printf("0x%02x, ", v);
-      v = gfmul(v,2);
-      if ( v == 1 ) v = 0;     /* For entry 255, not a real entry */
-    }
-    printf("\n");
-  }
-  printf("};\n");
-
-  /* Compute inverse table x^-1 == x^254 */
-  printf("\nconst u8 __attribute__((aligned(256)))\n"
-        "raid6_gfinv[256] =\n"
-        "{\n");
-  for ( i = 0 ; i < 256 ; i += 8 ) {
-    printf("\t");
-    for ( j = 0 ; j < 8 ; j++ ) {
-      invtbl[i+j] = v = gfpow(i+j,254);
-      printf("0x%02x, ", v);
-    }
-    printf("\n");
-  }
-  printf("};\n");
-
-  /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
-  printf("\nconst u8 __attribute__((aligned(256)))\n"
-        "raid6_gfexi[256] =\n"
-        "{\n");
-  for ( i = 0 ; i < 256 ; i += 8 ) {
-    printf("\t");
-    for ( j = 0 ; j < 8 ; j++ ) {
-      printf("0x%02x, ", invtbl[exptbl[i+j]^1]);
-    }
-    printf("\n");
-  }
-  printf("};\n\n");
-
-  return 0;
+       int i, j, k;
+       uint8_t v;
+       uint8_t exptbl[256], invtbl[256];
+
+       printf("#include \"raid6.h\"\n");
+
+       /* Compute multiplication table */
+       printf("\nconst u8  __attribute__((aligned(256)))\n"
+               "raid6_gfmul[256][256] =\n"
+               "{\n");
+       for (i = 0; i < 256; i++) {
+               printf("\t{\n");
+               for (j = 0; j < 256; j += 8) {
+                       printf("\t\t");
+                       for (k = 0; k < 8; k++)
+                               printf("0x%02x,%c", gfmul(i, j + k),
+                                      (k == 7) ? '\n' : ' ');
+               }
+               printf("\t},\n");
+       }
+       printf("};\n");
+
+       /* Compute power-of-2 table (exponent) */
+       v = 1;
+       printf("\nconst u8 __attribute__((aligned(256)))\n"
+              "raid6_gfexp[256] =\n" "{\n");
+       for (i = 0; i < 256; i += 8) {
+               printf("\t");
+               for (j = 0; j < 8; j++) {
+                       exptbl[i + j] = v;
+                       printf("0x%02x,%c", v, (j == 7) ? '\n' : ' ');
+                       v = gfmul(v, 2);
+                       if (v == 1)
+                               v = 0;  /* For entry 255, not a real entry */
+               }
+       }
+       printf("};\n");
+
+       /* Compute inverse table x^-1 == x^254 */
+       printf("\nconst u8 __attribute__((aligned(256)))\n"
+              "raid6_gfinv[256] =\n" "{\n");
+       for (i = 0; i < 256; i += 8) {
+               printf("\t");
+               for (j = 0; j < 8; j++) {
+                       invtbl[i + j] = v = gfpow(i + j, 254);
+                       printf("0x%02x,%c", v, (j == 7) ? '\n' : ' ');
+               }
+       }
+       printf("};\n");
+
+       /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
+       printf("\nconst u8 __attribute__((aligned(256)))\n"
+              "raid6_gfexi[256] =\n" "{\n");
+       for (i = 0; i < 256; i += 8) {
+               printf("\t");
+               for (j = 0; j < 8; j++)
+                       printf("0x%02x,%c", invtbl[exptbl[i + j] ^ 1],
+                              (j == 7) ? '\n' : ' ');
+       }
+       printf("};\n");
+
+       return 0;
 }
index eb631ebed6860b3f19ae8c3161a10e509d448d3e..3f299d835a2b1956e210c0a383e65f2d9c70874f 100644 (file)
@@ -436,7 +436,7 @@ static int multipath_run (mddev_t *mddev)
        }
 
        conf->working_disks = 0;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                disk_idx = rdev->raid_disk;
                if (disk_idx < 0 ||
                    disk_idx >= mddev->raid_disks)
index f8e591708d1fa7768fda354aa8da006b1f26d549..818b4828409667d5a40b53efb734575dd00ee3a2 100644 (file)
@@ -72,11 +72,11 @@ static int create_strip_zones (mddev_t *mddev)
         */
        conf->nr_strip_zones = 0;
  
-       ITERATE_RDEV(mddev,rdev1,tmp1) {
+       rdev_for_each(rdev1, tmp1, mddev) {
                printk("raid0: looking at %s\n",
                        bdevname(rdev1->bdev,b));
                c = 0;
-               ITERATE_RDEV(mddev,rdev2,tmp2) {
+               rdev_for_each(rdev2, tmp2, mddev) {
                        printk("raid0:   comparing %s(%llu)",
                               bdevname(rdev1->bdev,b),
                               (unsigned long long)rdev1->size);
@@ -124,7 +124,7 @@ static int create_strip_zones (mddev_t *mddev)
        cnt = 0;
        smallest = NULL;
        zone->dev = conf->devlist;
-       ITERATE_RDEV(mddev, rdev1, tmp1) {
+       rdev_for_each(rdev1, tmp1, mddev) {
                int j = rdev1->raid_disk;
 
                if (j < 0 || j >= mddev->raid_disks) {
@@ -293,7 +293,7 @@ static int raid0_run (mddev_t *mddev)
 
        /* calculate array device size */
        mddev->array_size = 0;
-       ITERATE_RDEV(mddev,rdev,tmp)
+       rdev_for_each(rdev, tmp, mddev)
                mddev->array_size += rdev->size;
 
        printk("raid0 : md_size is %llu blocks.\n", 
index 4a69c416e045c97f24ef4582c9d3b9f83588ba15..5c7fef091cec800da3f3cb482f7e97f574cb43c6 100644 (file)
@@ -1684,6 +1684,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        if (!go_faster && conf->nr_waiting)
                msleep_interruptible(1000);
 
+       bitmap_cond_end_sync(mddev->bitmap, sector_nr);
        raise_barrier(conf);
 
        conf->next_resync = sector_nr;
@@ -1766,6 +1767,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                return rv;
        }
 
+       if (max_sector > mddev->resync_max)
+               max_sector = mddev->resync_max; /* Don't do IO beyond here */
        nr_sectors = 0;
        sync_blocks = 0;
        do {
@@ -1884,7 +1887,7 @@ static int run(mddev_t *mddev)
        if (!conf->r1bio_pool)
                goto out_no_mem;
 
-       ITERATE_RDEV(mddev, rdev, tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                disk_idx = rdev->raid_disk;
                if (disk_idx >= mddev->raid_disks
                    || disk_idx < 0)
index 5cdcc938620050b39fb30593565847859d6ad1a4..017f58113c33604e381a5fcc7c75f01344f67841 100644 (file)
@@ -1657,6 +1657,9 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                return (max_sector - sector_nr) + sectors_skipped;
        }
 
+       if (max_sector > mddev->resync_max)
+               max_sector = mddev->resync_max; /* Don't do IO beyond here */
+
        /* make sure whole request will fit in a chunk - if chunks
         * are meaningful
         */
@@ -1670,6 +1673,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        if (!go_faster && conf->nr_waiting)
                msleep_interruptible(1000);
 
+       bitmap_cond_end_sync(mddev->bitmap, sector_nr);
+
        /* Again, very different code for resync and recovery.
         * Both must result in an r10bio with a list of bios that
         * have bi_end_io, bi_sector, bi_bdev set,
@@ -2021,7 +2026,7 @@ static int run(mddev_t *mddev)
                goto out_free_conf;
        }
 
-       ITERATE_RDEV(mddev, rdev, tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                disk_idx = rdev->raid_disk;
                if (disk_idx >= mddev->raid_disks
                    || disk_idx < 0)
index e8c8157b02fcb5e99a09786b977e30226e56ed95..2d6f1a51359cc490dcfd4f9b6bc5b1add12cf9a0 100644 (file)
@@ -3159,7 +3159,8 @@ static void raid5_activate_delayed(raid5_conf_t *conf)
                                atomic_inc(&conf->preread_active_stripes);
                        list_add_tail(&sh->lru, &conf->handle_list);
                }
-       }
+       } else
+               blk_plug_device(conf->mddev->queue);
 }
 
 static void activate_bit_delay(raid5_conf_t *conf)
@@ -3549,7 +3550,8 @@ static int make_request(struct request_queue *q, struct bio * bi)
                                goto retry;
                        }
                        finish_wait(&conf->wait_for_overlap, &w);
-                       handle_stripe(sh, NULL);
+                       set_bit(STRIPE_HANDLE, &sh->state);
+                       clear_bit(STRIPE_DELAYED, &sh->state);
                        release_stripe(sh);
                } else {
                        /* cannot get stripe for read-ahead, just give-up */
@@ -3698,6 +3700,25 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
                release_stripe(sh);
                first_sector += STRIPE_SECTORS;
        }
+       /* If this takes us to the resync_max point where we have to pause,
+        * then we need to write out the superblock.
+        */
+       sector_nr += conf->chunk_size>>9;
+       if (sector_nr >= mddev->resync_max) {
+               /* Cannot proceed until we've updated the superblock... */
+               wait_event(conf->wait_for_overlap,
+                          atomic_read(&conf->reshape_stripes) == 0);
+               mddev->reshape_position = conf->expand_progress;
+               set_bit(MD_CHANGE_DEVS, &mddev->flags);
+               md_wakeup_thread(mddev->thread);
+               wait_event(mddev->sb_wait,
+                          !test_bit(MD_CHANGE_DEVS, &mddev->flags)
+                          || kthread_should_stop());
+               spin_lock_irq(&conf->device_lock);
+               conf->expand_lo = mddev->reshape_position;
+               spin_unlock_irq(&conf->device_lock);
+               wake_up(&conf->wait_for_overlap);
+       }
        return conf->chunk_size>>9;
 }
 
@@ -3734,6 +3755,12 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
        if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
                return reshape_request(mddev, sector_nr, skipped);
 
+       /* No need to check resync_max as we never do more than one
+        * stripe, and as resync_max will always be on a chunk boundary,
+        * if the check in md_do_sync didn't fire, there is no chance
+        * of overstepping resync_max here
+        */
+
        /* if there is too many failed drives and we are trying
         * to resync, then assert that we are finished, because there is
         * nothing we can do.
@@ -3753,6 +3780,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
                return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */
        }
 
+
+       bitmap_cond_end_sync(mddev->bitmap, sector_nr);
+
        pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks);
        sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1);
        if (sh == NULL) {
@@ -3864,7 +3894,7 @@ static int  retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
  * During the scan, completed stripes are saved for us by the interrupt
  * handler, so that they will not have to wait for our next wakeup.
  */
-static void raid5d (mddev_t *mddev)
+static void raid5d(mddev_t *mddev)
 {
        struct stripe_head *sh;
        raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3889,12 +3919,6 @@ static void raid5d (mddev_t *mddev)
                        activate_bit_delay(conf);
                }
 
-               if (list_empty(&conf->handle_list) &&
-                   atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD &&
-                   !blk_queue_plugged(mddev->queue) &&
-                   !list_empty(&conf->delayed_list))
-                       raid5_activate_delayed(conf);
-
                while ((bio = remove_bio_from_retry(conf))) {
                        int ok;
                        spin_unlock_irq(&conf->device_lock);
@@ -4108,7 +4132,7 @@ static int run(mddev_t *mddev)
 
        pr_debug("raid5: run(%s) called.\n", mdname(mddev));
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                raid_disk = rdev->raid_disk;
                if (raid_disk >= conf->raid_disks
                    || raid_disk < 0)
@@ -4521,7 +4545,7 @@ static int raid5_start_reshape(mddev_t *mddev)
        if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
                return -EBUSY;
 
-       ITERATE_RDEV(mddev, rdev, rtmp)
+       rdev_for_each(rdev, rtmp, mddev)
                if (rdev->raid_disk < 0 &&
                    !test_bit(Faulty, &rdev->flags))
                        spares++;
@@ -4543,7 +4567,7 @@ static int raid5_start_reshape(mddev_t *mddev)
        /* Add some new drives, as many as will fit.
         * We know there are enough to make the newly sized array work.
         */
-       ITERATE_RDEV(mddev, rdev, rtmp)
+       rdev_for_each(rdev, rtmp, mddev)
                if (rdev->raid_disk < 0 &&
                    !test_bit(Faulty, &rdev->flags)) {
                        if (raid5_add_disk(mddev, rdev)) {
index 0d5cd57accd72fc38dc29d41b4725e4bd12880a0..559cc41b258566d4b0437241559156fbbc574721 100644 (file)
@@ -1,12 +1,10 @@
 /* -*- linux-c -*- ------------------------------------------------------- *
  *
- *   Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2002-2007 H. Peter Anvin - 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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
- *   (at your option) any later version; incorporated herein by reference.
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2 or (at your
+ *   option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
 
@@ -30,67 +28,87 @@ char *dataptrs[NDISKS];
 char data[NDISKS][PAGE_SIZE];
 char recovi[PAGE_SIZE], recovj[PAGE_SIZE];
 
-void makedata(void)
+static void makedata(void)
 {
        int i, j;
 
-       for (  i = 0 ; i < NDISKS ; i++ ) {
-               for ( j = 0 ; j < PAGE_SIZE ; j++ ) {
+       for (i = 0; i < NDISKS; i++) {
+               for (j = 0; j < PAGE_SIZE; j++)
                        data[i][j] = rand();
-               }
+
                dataptrs[i] = data[i];
        }
 }
 
+static char disk_type(int d)
+{
+       switch (d) {
+       case NDISKS-2:
+               return 'P';
+       case NDISKS-1:
+               return 'Q';
+       default:
+               return 'D';
+       }
+}
+
+static int test_disks(int i, int j)
+{
+       int erra, errb;
+
+       memset(recovi, 0xf0, PAGE_SIZE);
+       memset(recovj, 0xba, PAGE_SIZE);
+
+       dataptrs[i] = recovi;
+       dataptrs[j] = recovj;
+
+       raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs);
+
+       erra = memcmp(data[i], recovi, PAGE_SIZE);
+       errb = memcmp(data[j], recovj, PAGE_SIZE);
+
+       if (i < NDISKS-2 && j == NDISKS-1) {
+               /* We don't implement the DQ failure scenario, since it's
+                  equivalent to a RAID-5 failure (XOR, then recompute Q) */
+               erra = errb = 0;
+       } else {
+               printf("algo=%-8s  faila=%3d(%c)  failb=%3d(%c)  %s\n",
+                      raid6_call.name,
+                      i, disk_type(i),
+                      j, disk_type(j),
+                      (!erra && !errb) ? "OK" :
+                      !erra ? "ERRB" :
+                      !errb ? "ERRA" : "ERRAB");
+       }
+
+       dataptrs[i] = data[i];
+       dataptrs[j] = data[j];
+
+       return erra || errb;
+}
+
 int main(int argc, char *argv[])
 {
-       const struct raid6_calls * const * algo;
+       const struct raid6_calls *const *algo;
        int i, j;
-       int erra, errb;
+       int err = 0;
 
        makedata();
 
-       for ( algo = raid6_algos ; *algo ; algo++ ) {
-               if ( !(*algo)->valid || (*algo)->valid() ) {
+       for (algo = raid6_algos; *algo; algo++) {
+               if (!(*algo)->valid || (*algo)->valid()) {
                        raid6_call = **algo;
 
                        /* Nuke syndromes */
                        memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE);
 
                        /* Generate assumed good syndrome */
-                       raid6_call.gen_syndrome(NDISKS, PAGE_SIZE, (void **)&dataptrs);
-
-                       for ( i = 0 ; i < NDISKS-1 ; i++ ) {
-                               for ( j = i+1 ; j < NDISKS ; j++ ) {
-                                       memset(recovi, 0xf0, PAGE_SIZE);
-                                       memset(recovj, 0xba, PAGE_SIZE);
-
-                                       dataptrs[i] = recovi;
-                                       dataptrs[j] = recovj;
-
-                                       raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs);
-
-                                       erra = memcmp(data[i], recovi, PAGE_SIZE);
-                                       errb = memcmp(data[j], recovj, PAGE_SIZE);
-
-                                       if ( i < NDISKS-2 && j == NDISKS-1 ) {
-                                               /* We don't implement the DQ failure scenario, since it's
-                                                  equivalent to a RAID-5 failure (XOR, then recompute Q) */
-                                       } else {
-                                               printf("algo=%-8s  faila=%3d(%c)  failb=%3d(%c)  %s\n",
-                                                      raid6_call.name,
-                                                      i, (i==NDISKS-2)?'P':'D',
-                                                      j, (j==NDISKS-1)?'Q':(j==NDISKS-2)?'P':'D',
-                                                      (!erra && !errb) ? "OK" :
-                                                      !erra ? "ERRB" :
-                                                      !errb ? "ERRA" :
-                                                      "ERRAB");
-                                       }
-
-                                       dataptrs[i] = data[i];
-                                       dataptrs[j] = data[j];
-                               }
-                       }
+                       raid6_call.gen_syndrome(NDISKS, PAGE_SIZE,
+                                               (void **)&dataptrs);
+
+                       for (i = 0; i < NDISKS-1; i++)
+                               for (j = i+1; j < NDISKS; j++)
+                                       err += test_disks(i, j);
                }
                printf("\n");
        }
@@ -99,5 +117,8 @@ int main(int argc, char *argv[])
        /* Pick the best algorithm test */
        raid6_select_algo();
 
-       return 0;
+       if (err)
+               printf("\n*** ERRORS FOUND ***\n");
+
+       return err;
 }
index 28ddd146c1c52a208222945cd816a0504db3431b..850b8c6f457783e0a9282b230615b772d7e5104c 100644 (file)
@@ -22,7 +22,6 @@ obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
-obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
deleted file mode 100644 (file)
index 9fa5b70..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/kdev_t.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-
-#include <asm/semaphore.h>
-#include <asm/uaccess.h>
-
-
-#define DEV_MAX  4
-
-static int devnr = -1;
-module_param(devnr, int, 0644);
-
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/* ----------------------------------------------------------------------- */
-
-struct TVMIXER {
-       struct i2c_client *dev;
-       int minor;
-       int count;
-};
-
-static struct TVMIXER devices[DEV_MAX];
-
-static int tvmixer_adapters(struct i2c_adapter *adap);
-static int tvmixer_clients(struct i2c_client *client);
-
-/* ----------------------------------------------------------------------- */
-
-static int mix_to_v4l(int i)
-{
-       int r;
-
-       r = ((i & 0xff) * 65536 + 50) / 100;
-       if (r > 65535) r = 65535;
-       if (r <     0) r =     0;
-       return r;
-}
-
-static int v4l_to_mix(int i)
-{
-       int r;
-
-       r = (i * 100 + 32768) / 65536;
-       if (r > 100) r = 100;
-       if (r <   0) r =   0;
-       return r | (r << 8);
-}
-
-static int v4l_to_mix2(int l, int r)
-{
-       r = (r * 100 + 32768) / 65536;
-       if (r > 100) r = 100;
-       if (r <   0) r =   0;
-       l = (l * 100 + 32768) / 65536;
-       if (l > 100) l = 100;
-       if (l <   0) l =   0;
-       return (r << 8) | l;
-}
-
-static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct video_audio va;
-       int left,right,ret,val = 0;
-       struct TVMIXER *mix = file->private_data;
-       struct i2c_client *client = mix->dev;
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-
-       if (NULL == client)
-               return -ENODEV;
-
-       if (cmd == SOUND_MIXER_INFO) {
-               mixer_info info;
-               strlcpy(info.id, "tv card", sizeof(info.id));
-               strlcpy(info.name, client->name, sizeof(info.name));
-               info.modify_counter = 42 /* FIXME */;
-               if (copy_to_user(argp, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       if (cmd == SOUND_OLD_MIXER_INFO) {
-               _old_mixer_info info;
-               strlcpy(info.id, "tv card", sizeof(info.id));
-               strlcpy(info.name, client->name, sizeof(info.name));
-               if (copy_to_user(argp, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       if (cmd == OSS_GETVERSION)
-               return put_user(SOUND_VERSION, p);
-
-       if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-               if (get_user(val, p))
-                       return -EFAULT;
-
-       /* read state */
-       memset(&va,0,sizeof(va));
-       client->driver->command(client,VIDIOCGAUDIO,&va);
-
-       switch (cmd) {
-       case MIXER_READ(SOUND_MIXER_RECMASK):
-       case MIXER_READ(SOUND_MIXER_CAPS):
-       case MIXER_READ(SOUND_MIXER_RECSRC):
-       case MIXER_WRITE(SOUND_MIXER_RECSRC):
-               ret = 0;
-               break;
-
-       case MIXER_READ(SOUND_MIXER_STEREODEVS):
-               ret = SOUND_MASK_VOLUME;
-               break;
-       case MIXER_READ(SOUND_MIXER_DEVMASK):
-               ret = SOUND_MASK_VOLUME;
-               if (va.flags & VIDEO_AUDIO_BASS)
-                       ret |= SOUND_MASK_BASS;
-               if (va.flags & VIDEO_AUDIO_TREBLE)
-                       ret |= SOUND_MASK_TREBLE;
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_VOLUME):
-               left  = mix_to_v4l(val);
-               right = mix_to_v4l(val >> 8);
-               va.volume  = max(left,right);
-               va.balance = (32768*min(left,right)) / (va.volume ? va.volume : 1);
-               va.balance = (left<right) ? (65535-va.balance) : va.balance;
-               if (va.volume)
-                       va.flags &= ~VIDEO_AUDIO_MUTE;
-               client->driver->command(client,VIDIOCSAUDIO,&va);
-               client->driver->command(client,VIDIOCGAUDIO,&va);
-               /* fall throuth */
-       case MIXER_READ(SOUND_MIXER_VOLUME):
-               left  = (min(65536 - va.balance,32768) *
-                        va.volume) / 32768;
-               right = (min(va.balance,(u16)32768) *
-                        va.volume) / 32768;
-               ret = v4l_to_mix2(left,right);
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_BASS):
-               va.bass = mix_to_v4l(val);
-               client->driver->command(client,VIDIOCSAUDIO,&va);
-               client->driver->command(client,VIDIOCGAUDIO,&va);
-               /* fall throuth  */
-       case MIXER_READ(SOUND_MIXER_BASS):
-               ret = v4l_to_mix(va.bass);
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_TREBLE):
-               va.treble = mix_to_v4l(val);
-               client->driver->command(client,VIDIOCSAUDIO,&va);
-               client->driver->command(client,VIDIOCGAUDIO,&va);
-               /* fall throuth */
-       case MIXER_READ(SOUND_MIXER_TREBLE):
-               ret = v4l_to_mix(va.treble);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-       if (put_user(ret, p))
-               return -EFAULT;
-       return 0;
-}
-
-static int tvmixer_open(struct inode *inode, struct file *file)
-{
-       int i, minor = iminor(inode);
-       struct TVMIXER *mix = NULL;
-       struct i2c_client *client = NULL;
-
-       for (i = 0; i < DEV_MAX; i++) {
-               if (devices[i].minor == minor) {
-                       mix = devices+i;
-                       client = mix->dev;
-                       break;
-               }
-       }
-
-       if (NULL == client)
-               return -ENODEV;
-
-       /* lock bttv in memory while the mixer is in use  */
-       file->private_data = mix;
-       if (client->adapter->owner)
-               try_module_get(client->adapter->owner);
-       return 0;
-}
-
-static int tvmixer_release(struct inode *inode, struct file *file)
-{
-       struct TVMIXER *mix = file->private_data;
-       struct i2c_client *client;
-
-       client = mix->dev;
-       if (NULL == client) {
-               return -ENODEV;
-       }
-
-       module_put(client->adapter->owner);
-       return 0;
-}
-
-static struct i2c_driver driver = {
-       .driver = {
-               .name    = "tvmixer",
-       },
-       .id              = I2C_DRIVERID_TVMIXER,
-       .detach_adapter  = tvmixer_adapters,
-       .attach_adapter  = tvmixer_adapters,
-       .detach_client   = tvmixer_clients,
-};
-
-static const struct file_operations tvmixer_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .ioctl          = tvmixer_ioctl,
-       .open           = tvmixer_open,
-       .release        = tvmixer_release,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static int tvmixer_adapters(struct i2c_adapter *adap)
-{
-       struct i2c_client *client;
-
-       list_for_each_entry(client, &adap->clients, list)
-               tvmixer_clients(client);
-       return 0;
-}
-
-static int tvmixer_clients(struct i2c_client *client)
-{
-       struct video_audio va;
-       int i,minor;
-
-       if (!(client->adapter->class & I2C_CLASS_TV_ANALOG))
-               return -1;
-
-       /* unregister ?? */
-       for (i = 0; i < DEV_MAX; i++) {
-               if (devices[i].dev == client) {
-                       /* unregister */
-                       unregister_sound_mixer(devices[i].minor);
-                       devices[i].dev = NULL;
-                       devices[i].minor = -1;
-                       printk("tvmixer: %s unregistered (#1)\n",
-                              client->name);
-                       return 0;
-               }
-       }
-
-       /* look for a free slot */
-       for (i = 0; i < DEV_MAX; i++)
-               if (NULL == devices[i].dev)
-                       break;
-       if (i == DEV_MAX) {
-               printk(KERN_WARNING "tvmixer: DEV_MAX too small\n");
-               return -1;
-       }
-
-       /* audio chip with mixer ??? */
-       if (NULL == client->driver->command)
-               return -1;
-       memset(&va,0,sizeof(va));
-       if (0 != client->driver->command(client,VIDIOCGAUDIO,&va))
-               return -1;
-       if (0 == (va.flags & VIDEO_AUDIO_VOLUME))
-               return -1;
-
-       /* everything is fine, register */
-       if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) {
-               printk(KERN_ERR "tvmixer: cannot allocate mixer device\n");
-               return -1;
-       }
-
-       devices[i].minor = minor;
-       devices[i].count = 0;
-       devices[i].dev   = client;
-       printk("tvmixer: %s (%s) registered with minor %d\n",
-              client->name,client->adapter->name,minor);
-
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int __init tvmixer_init_module(void)
-{
-       int i;
-
-       for (i = 0; i < DEV_MAX; i++)
-               devices[i].minor = -1;
-
-       return i2c_add_driver(&driver);
-}
-
-static void __exit tvmixer_cleanup_module(void)
-{
-       int i;
-
-       i2c_del_driver(&driver);
-       for (i = 0; i < DEV_MAX; i++) {
-               if (devices[i].minor != -1) {
-                       unregister_sound_mixer(devices[i].minor);
-                       printk("tvmixer: %s unregistered (#2)\n",
-                              devices[i].dev->name);
-               }
-       }
-}
-
-module_init(tvmixer_init_module);
-module_exit(tvmixer_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 25716193a534db2d4fb16c00cca5b1a94c481c6a..0c886c8823854b5411af4c9a6f1aaf222f5d11e4 100644 (file)
@@ -15,6 +15,13 @@ config MFD_SM501
          interface. The device may be connected by PCI or local bus with
          varying functions enabled.
 
+config MFD_ASIC3
+       bool "Support for Compaq ASIC3"
+       depends on GENERIC_HARDIRQS && ARM
+        ---help---
+         This driver supports the ASIC3 multifunction chip found on many
+         PDAs (mainly iPAQ and HTC based ones)
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
index 51432091b323f9edad3fedfa0a0fad5269a9a9f9..521cd5cb68af3fc8a5692270f27f8f1e866f974d 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_MFD_SM501)                += sm501.o
+obj-$(CONFIG_MFD_ASIC3)                += asic3.o
 
 obj-$(CONFIG_MCP)              += mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)       += mcp-sa11x0.o
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
new file mode 100644 (file)
index 0000000..63fb1ff
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * driver/mfd/asic3.c
+ *
+ * Compaq ASIC3 support.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ * Copyright 2004-2005 Phil Blundell
+ * Copyright 2007 OpenedHand Ltd.
+ *
+ * Authors: Phil Blundell <pb@handhelds.org>,
+ *         Samuel Ortiz <sameo@openedhand.com>
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/asic3.h>
+
+static inline void asic3_write_register(struct asic3 *asic,
+                                unsigned int reg, u32 value)
+{
+       iowrite16(value, (unsigned long)asic->mapping +
+                 (reg >> asic->bus_shift));
+}
+
+static inline u32 asic3_read_register(struct asic3 *asic,
+                              unsigned int reg)
+{
+       return ioread16((unsigned long)asic->mapping +
+                       (reg >> asic->bus_shift));
+}
+
+/* IRQs */
+#define MAX_ASIC_ISR_LOOPS    20
+#define ASIC3_GPIO_Base_INCR \
+       (ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base)
+
+static void asic3_irq_flip_edge(struct asic3 *asic,
+                               u32 base, int bit)
+{
+       u16 edge;
+       unsigned long flags;
+
+       spin_lock_irqsave(&asic->lock, flags);
+       edge = asic3_read_register(asic,
+                                  base + ASIC3_GPIO_EdgeTrigger);
+       edge ^= bit;
+       asic3_write_register(asic,
+                            base + ASIC3_GPIO_EdgeTrigger, edge);
+       spin_unlock_irqrestore(&asic->lock, flags);
+}
+
+static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+       int iter, i;
+       unsigned long flags;
+       struct asic3 *asic;
+
+       desc->chip->ack(irq);
+
+       asic = desc->handler_data;
+
+       for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) {
+               u32 status;
+               int bank;
+
+               spin_lock_irqsave(&asic->lock, flags);
+               status = asic3_read_register(asic,
+                                            ASIC3_OFFSET(INTR, PIntStat));
+               spin_unlock_irqrestore(&asic->lock, flags);
+
+               /* Check all ten register bits */
+               if ((status & 0x3ff) == 0)
+                       break;
+
+               /* Handle GPIO IRQs */
+               for (bank = 0; bank < ASIC3_NUM_GPIO_BANKS; bank++) {
+                       if (status & (1 << bank)) {
+                               unsigned long base, istat;
+
+                               base = ASIC3_GPIO_A_Base
+                                      + bank * ASIC3_GPIO_Base_INCR;
+
+                               spin_lock_irqsave(&asic->lock, flags);
+                               istat = asic3_read_register(asic,
+                                                           base +
+                                                           ASIC3_GPIO_IntStatus);
+                               /* Clearing IntStatus */
+                               asic3_write_register(asic,
+                                                    base +
+                                                    ASIC3_GPIO_IntStatus, 0);
+                               spin_unlock_irqrestore(&asic->lock, flags);
+
+                               for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) {
+                                       int bit = (1 << i);
+                                       unsigned int irqnr;
+
+                                       if (!(istat & bit))
+                                               continue;
+
+                                       irqnr = asic->irq_base +
+                                               (ASIC3_GPIOS_PER_BANK * bank)
+                                               + i;
+                                       desc = irq_desc + irqnr;
+                                       desc->handle_irq(irqnr, desc);
+                                       if (asic->irq_bothedge[bank] & bit)
+                                               asic3_irq_flip_edge(asic, base,
+                                                                   bit);
+                               }
+                       }
+               }
+
+               /* Handle remaining IRQs in the status register */
+               for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) {
+                       /* They start at bit 4 and go up */
+                       if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) {
+                               desc = irq_desc +  + i;
+                               desc->handle_irq(asic->irq_base + i,
+                                                desc);
+                       }
+               }
+       }
+
+       if (iter >= MAX_ASIC_ISR_LOOPS)
+               printk(KERN_ERR "%s: interrupt processing overrun\n",
+                      __FUNCTION__);
+}
+
+static inline int asic3_irq_to_bank(struct asic3 *asic, int irq)
+{
+       int n;
+
+       n = (irq - asic->irq_base) >> 4;
+
+       return (n * (ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base));
+}
+
+static inline int asic3_irq_to_index(struct asic3 *asic, int irq)
+{
+       return (irq - asic->irq_base) & 0xf;
+}
+
+static void asic3_mask_gpio_irq(unsigned int irq)
+{
+       struct asic3 *asic = get_irq_chip_data(irq);
+       u32 val, bank, index;
+       unsigned long flags;
+
+       bank = asic3_irq_to_bank(asic, irq);
+       index = asic3_irq_to_index(asic, irq);
+
+       spin_lock_irqsave(&asic->lock, flags);
+       val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask);
+       val |= 1 << index;
+       asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val);
+       spin_unlock_irqrestore(&asic->lock, flags);
+}
+
+static void asic3_mask_irq(unsigned int irq)
+{
+       struct asic3 *asic = get_irq_chip_data(irq);
+       int regval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&asic->lock, flags);
+       regval = asic3_read_register(asic,
+                                    ASIC3_INTR_Base +
+                                    ASIC3_INTR_IntMask);
+
+       regval &= ~(ASIC3_INTMASK_MASK0 <<
+                   (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+
+       asic3_write_register(asic,
+                            ASIC3_INTR_Base +
+                            ASIC3_INTR_IntMask,
+                            regval);
+       spin_unlock_irqrestore(&asic->lock, flags);
+}
+
+static void asic3_unmask_gpio_irq(unsigned int irq)
+{
+       struct asic3 *asic = get_irq_chip_data(irq);
+       u32 val, bank, index;
+       unsigned long flags;
+
+       bank = asic3_irq_to_bank(asic, irq);
+       index = asic3_irq_to_index(asic, irq);
+
+       spin_lock_irqsave(&asic->lock, flags);
+       val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask);
+       val &= ~(1 << index);
+       asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val);
+       spin_unlock_irqrestore(&asic->lock, flags);
+}
+
+static void asic3_unmask_irq(unsigned int irq)
+{
+       struct asic3 *asic = get_irq_chip_data(irq);
+       int regval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&asic->lock, flags);
+       regval = asic3_read_register(asic,
+                                    ASIC3_INTR_Base +
+                                    ASIC3_INTR_IntMask);
+
+       regval |= (ASIC3_INTMASK_MASK0 <<
+                  (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+
+       asic3_write_register(asic,
+                            ASIC3_INTR_Base +
+                            ASIC3_INTR_IntMask,
+                            regval);
+       spin_unlock_irqrestore(&asic->lock, flags);
+}
+
+static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+       struct asic3 *asic = get_irq_chip_data(irq);
+       u32 bank, index;
+       u16 trigger, level, edge, bit;
+       unsigned long flags;
+
+       bank = asic3_irq_to_bank(asic, irq);
+       index = asic3_irq_to_index(asic, irq);
+       bit = 1<<index;
+
+       spin_lock_irqsave(&asic->lock, flags);
+       level = asic3_read_register(asic,
+                                   bank + ASIC3_GPIO_LevelTrigger);
+       edge = asic3_read_register(asic,
+                                  bank + ASIC3_GPIO_EdgeTrigger);
+       trigger = asic3_read_register(asic,
+                                     bank + ASIC3_GPIO_TriggerType);
+       asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
+
+       if (type == IRQT_RISING) {
+               trigger |= bit;
+               edge |= bit;
+       } else if (type == IRQT_FALLING) {
+               trigger |= bit;
+               edge &= ~bit;
+       } else if (type == IRQT_BOTHEDGE) {
+               trigger |= bit;
+               if (asic3_gpio_get_value(asic, irq - asic->irq_base))
+                       edge &= ~bit;
+               else
+                       edge |= bit;
+               asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit;
+       } else if (type == IRQT_LOW) {
+               trigger &= ~bit;
+               level &= ~bit;
+       } else if (type == IRQT_HIGH) {
+               trigger &= ~bit;
+               level |= bit;
+       } else {
+               /*
+                * if type == IRQT_NOEDGE, we should mask interrupts, but
+                * be careful to not unmask them if mask was also called.
+                * Probably need internal state for mask.
+                */
+               printk(KERN_NOTICE "asic3: irq type not changed.\n");
+       }
+       asic3_write_register(asic, bank + ASIC3_GPIO_LevelTrigger,
+                            level);
+       asic3_write_register(asic, bank + ASIC3_GPIO_EdgeTrigger,
+                            edge);
+       asic3_write_register(asic, bank + ASIC3_GPIO_TriggerType,
+                            trigger);
+       spin_unlock_irqrestore(&asic->lock, flags);
+       return 0;
+}
+
+static struct irq_chip asic3_gpio_irq_chip = {
+       .name           = "ASIC3-GPIO",
+       .ack            = asic3_mask_gpio_irq,
+       .mask           = asic3_mask_gpio_irq,
+       .unmask         = asic3_unmask_gpio_irq,
+       .set_type       = asic3_gpio_irq_type,
+};
+
+static struct irq_chip asic3_irq_chip = {
+       .name           = "ASIC3",
+       .ack            = asic3_mask_irq,
+       .mask           = asic3_mask_irq,
+       .unmask         = asic3_unmask_irq,
+};
+
+static int asic3_irq_probe(struct platform_device *pdev)
+{
+       struct asic3 *asic = platform_get_drvdata(pdev);
+       unsigned long clksel = 0;
+       unsigned int irq, irq_base;
+
+       asic->irq_nr = platform_get_irq(pdev, 0);
+       if (asic->irq_nr < 0)
+               return asic->irq_nr;
+
+       /* turn on clock to IRQ controller */
+       clksel |= CLOCK_SEL_CX;
+       asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL),
+                            clksel);
+
+       irq_base = asic->irq_base;
+
+       for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) {
+               if (irq < asic->irq_base + ASIC3_NUM_GPIOS)
+                       set_irq_chip(irq, &asic3_gpio_irq_chip);
+               else
+                       set_irq_chip(irq, &asic3_irq_chip);
+
+               set_irq_chip_data(irq, asic);
+               set_irq_handler(irq, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+       }
+
+       asic3_write_register(asic, ASIC3_OFFSET(INTR, IntMask),
+                            ASIC3_INTMASK_GINTMASK);
+
+       set_irq_chained_handler(asic->irq_nr, asic3_irq_demux);
+       set_irq_type(asic->irq_nr, IRQT_RISING);
+       set_irq_data(asic->irq_nr, asic);
+
+       return 0;
+}
+
+static void asic3_irq_remove(struct platform_device *pdev)
+{
+       struct asic3 *asic = platform_get_drvdata(pdev);
+       unsigned int irq, irq_base;
+
+       irq_base = asic->irq_base;
+
+       for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) {
+               set_irq_flags(irq, 0);
+               set_irq_handler(irq, NULL);
+               set_irq_chip(irq, NULL);
+               set_irq_chip_data(irq, NULL);
+       }
+       set_irq_chained_handler(asic->irq_nr, NULL);
+}
+
+/* GPIOs */
+static inline u32 asic3_get_gpio(struct asic3 *asic, unsigned int base,
+                                unsigned int function)
+{
+       return asic3_read_register(asic, base + function);
+}
+
+static void asic3_set_gpio(struct asic3 *asic, unsigned int base,
+                          unsigned int function, u32 bits, u32 val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&asic->lock, flags);
+       val |= (asic3_read_register(asic, base + function) & ~bits);
+
+       asic3_write_register(asic, base + function, val);
+       spin_unlock_irqrestore(&asic->lock, flags);
+}
+
+#define asic3_get_gpio_a(asic, fn) \
+       asic3_get_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn)
+#define asic3_get_gpio_b(asic, fn) \
+       asic3_get_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn)
+#define asic3_get_gpio_c(asic, fn) \
+       asic3_get_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn)
+#define asic3_get_gpio_d(asic, fn) \
+       asic3_get_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn)
+
+#define asic3_set_gpio_a(asic, fn, bits, val) \
+       asic3_set_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn, bits, val)
+#define asic3_set_gpio_b(asic, fn, bits, val) \
+       asic3_set_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn, bits, val)
+#define asic3_set_gpio_c(asic, fn, bits, val) \
+       asic3_set_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn, bits, val)
+#define asic3_set_gpio_d(asic, fn, bits, val) \
+       asic3_set_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn, bits, val)
+
+#define asic3_set_gpio_banks(asic, fn, bits, pdata, field)               \
+       do {                                                              \
+            asic3_set_gpio_a((asic), fn, (bits), (pdata)->gpio_a.field); \
+            asic3_set_gpio_b((asic), fn, (bits), (pdata)->gpio_b.field); \
+            asic3_set_gpio_c((asic), fn, (bits), (pdata)->gpio_c.field); \
+            asic3_set_gpio_d((asic), fn, (bits), (pdata)->gpio_d.field); \
+       } while (0)
+
+int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio)
+{
+       u32 mask = ASIC3_GPIO_bit(gpio);
+
+       switch (gpio >> 4) {
+       case ASIC3_GPIO_BANK_A:
+               return asic3_get_gpio_a(asic, Status) & mask;
+       case ASIC3_GPIO_BANK_B:
+               return asic3_get_gpio_b(asic, Status) & mask;
+       case ASIC3_GPIO_BANK_C:
+               return asic3_get_gpio_c(asic, Status) & mask;
+       case ASIC3_GPIO_BANK_D:
+               return asic3_get_gpio_d(asic, Status) & mask;
+       default:
+               printk(KERN_ERR "%s: invalid GPIO value 0x%x",
+                      __FUNCTION__, gpio);
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL(asic3_gpio_get_value);
+
+void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val)
+{
+       u32 mask = ASIC3_GPIO_bit(gpio);
+       u32 bitval = 0;
+       if (val)
+               bitval = mask;
+
+       switch (gpio >> 4) {
+       case ASIC3_GPIO_BANK_A:
+               asic3_set_gpio_a(asic, Out, mask, bitval);
+               return;
+       case ASIC3_GPIO_BANK_B:
+               asic3_set_gpio_b(asic, Out, mask, bitval);
+               return;
+       case ASIC3_GPIO_BANK_C:
+               asic3_set_gpio_c(asic, Out, mask, bitval);
+               return;
+       case ASIC3_GPIO_BANK_D:
+               asic3_set_gpio_d(asic, Out, mask, bitval);
+               return;
+       default:
+               printk(KERN_ERR "%s: invalid GPIO value 0x%x",
+                      __FUNCTION__, gpio);
+               return;
+       }
+}
+EXPORT_SYMBOL(asic3_gpio_set_value);
+
+static int asic3_gpio_probe(struct platform_device *pdev)
+{
+       struct asic3_platform_data *pdata = pdev->dev.platform_data;
+       struct asic3 *asic = platform_get_drvdata(pdev);
+
+       asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, Mask), 0xffff);
+       asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, Mask), 0xffff);
+       asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, Mask), 0xffff);
+       asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, Mask), 0xffff);
+
+       asic3_set_gpio_a(asic, SleepMask, 0xffff, 0xffff);
+       asic3_set_gpio_b(asic, SleepMask, 0xffff, 0xffff);
+       asic3_set_gpio_c(asic, SleepMask, 0xffff, 0xffff);
+       asic3_set_gpio_d(asic, SleepMask, 0xffff, 0xffff);
+
+       if (pdata) {
+               asic3_set_gpio_banks(asic, Out, 0xffff, pdata, init);
+               asic3_set_gpio_banks(asic, Direction, 0xffff, pdata, dir);
+               asic3_set_gpio_banks(asic, SleepMask, 0xffff, pdata,
+                                    sleep_mask);
+               asic3_set_gpio_banks(asic, SleepOut, 0xffff, pdata, sleep_out);
+               asic3_set_gpio_banks(asic, BattFaultOut, 0xffff, pdata,
+                                    batt_fault_out);
+               asic3_set_gpio_banks(asic, SleepConf, 0xffff, pdata,
+                                    sleep_conf);
+               asic3_set_gpio_banks(asic, AltFunction, 0xffff, pdata,
+                                    alt_function);
+       }
+
+       return 0;
+}
+
+static void asic3_gpio_remove(struct platform_device *pdev)
+{
+       return;
+}
+
+
+/* Core */
+static int asic3_probe(struct platform_device *pdev)
+{
+       struct asic3_platform_data *pdata = pdev->dev.platform_data;
+       struct asic3 *asic;
+       struct resource *mem;
+       unsigned long clksel;
+       int ret;
+
+       asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
+       if (!asic)
+               return -ENOMEM;
+
+       spin_lock_init(&asic->lock);
+       platform_set_drvdata(pdev, asic);
+       asic->dev = &pdev->dev;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               ret = -ENOMEM;
+               printk(KERN_ERR "asic3: no MEM resource\n");
+               goto err_out_1;
+       }
+
+       asic->mapping = ioremap(mem->start, PAGE_SIZE);
+       if (!asic->mapping) {
+               ret = -ENOMEM;
+               printk(KERN_ERR "asic3: couldn't ioremap\n");
+               goto err_out_1;
+       }
+
+       asic->irq_base = pdata->irq_base;
+
+       if (pdata && pdata->bus_shift)
+               asic->bus_shift = 2 - pdata->bus_shift;
+       else
+               asic->bus_shift = 0;
+
+       clksel = 0;
+       asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel);
+
+       ret = asic3_irq_probe(pdev);
+       if (ret < 0) {
+               printk(KERN_ERR "asic3: couldn't probe IRQs\n");
+               goto err_out_2;
+       }
+       asic3_gpio_probe(pdev);
+
+       if (pdata->children) {
+               int i;
+               for (i = 0; i < pdata->n_children; i++) {
+                       pdata->children[i]->dev.parent = &pdev->dev;
+                       platform_device_register(pdata->children[i]);
+               }
+       }
+
+       printk(KERN_INFO "ASIC3 Core driver\n");
+
+       return 0;
+
+ err_out_2:
+       iounmap(asic->mapping);
+ err_out_1:
+       kfree(asic);
+
+       return ret;
+}
+
+static int asic3_remove(struct platform_device *pdev)
+{
+       struct asic3 *asic = platform_get_drvdata(pdev);
+
+       asic3_gpio_remove(pdev);
+       asic3_irq_remove(pdev);
+
+       asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0);
+
+       iounmap(asic->mapping);
+
+       kfree(asic);
+
+       return 0;
+}
+
+static void asic3_shutdown(struct platform_device *pdev)
+{
+}
+
+static struct platform_driver asic3_device_driver = {
+       .driver         = {
+               .name   = "asic3",
+       },
+       .probe          = asic3_probe,
+       .remove         = __devexit_p(asic3_remove),
+       .shutdown       = asic3_shutdown,
+};
+
+static int __init asic3_init(void)
+{
+       int retval = 0;
+       retval = platform_driver_register(&asic3_device_driver);
+       return retval;
+}
+
+subsys_initcall(asic3_init);
index 7dce318df1bdb1751b061bbddc258ec4648743dc..0846c33296bc7e1a0da8aabf21a7023667613edb 100644 (file)
@@ -33,7 +33,6 @@
  *  Sam Lin        - GPS support
  */
 
-#include <linux/autoconf.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
index c8d62c268b11729dd2916105d26a8105fd01c905..1cfd7f3f129400fd9d8d22d429689d6d29234d4a 100644 (file)
@@ -50,7 +50,6 @@
 #include <linux/dmi.h>
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
-#include <linux/autoconf.h>
 
 #define FUJITSU_DRIVER_VERSION "0.3"
 
index 552b7957a92a1ad1ea284aedf0e02ad36d102a1c..c884730c5eafc55701486be80c13450f1f6a09e8 100644 (file)
@@ -129,27 +129,28 @@ module_param(cpoint_count, int, 0644);
 MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\
                                "crash point is to be hit to trigger action");
 
-unsigned int jp_do_irq(unsigned int irq)
+static unsigned int jp_do_irq(unsigned int irq)
 {
        lkdtm_handler();
        jprobe_return();
        return 0;
 }
 
-irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction *action)
+static irqreturn_t jp_handle_irq_event(unsigned int irq,
+                                      struct irqaction *action)
 {
        lkdtm_handler();
        jprobe_return();
        return 0;
 }
 
-void jp_tasklet_action(struct softirq_action *a)
+static void jp_tasklet_action(struct softirq_action *a)
 {
        lkdtm_handler();
        jprobe_return();
 }
 
-void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
+static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
 {
        lkdtm_handler();
        jprobe_return();
@@ -157,23 +158,24 @@ void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
 
 struct scan_control;
 
-unsigned long jp_shrink_inactive_list(unsigned long max_scan,
-                               struct zone *zone, struct scan_control *sc)
+static unsigned long jp_shrink_inactive_list(unsigned long max_scan,
+                                            struct zone *zone,
+                                            struct scan_control *sc)
 {
        lkdtm_handler();
        jprobe_return();
        return 0;
 }
 
-int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
-                               const enum hrtimer_mode mode)
+static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
+                           const enum hrtimer_mode mode)
 {
        lkdtm_handler();
        jprobe_return();
        return 0;
 }
 
-int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
+static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 {
        lkdtm_handler();
        jprobe_return();
@@ -270,7 +272,7 @@ void lkdtm_handler(void)
        }
 }
 
-int lkdtm_module_init(void)
+static int __init lkdtm_module_init(void)
 {
        int ret;
 
@@ -331,7 +333,7 @@ int lkdtm_module_init(void)
        return 0;
 }
 
-void lkdtm_module_exit(void)
+static void __exit lkdtm_module_exit(void)
 {
         unregister_jprobe(&lkdtm);
         printk(KERN_INFO "lkdtm : Crash point unregistered\n");
index 83679c7629253b2ed0b4b106ea0e17e3073ef0df..de898c6938f37acd6194d27c3706c36b193716a5 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/dmi.h>
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
-#include <linux/autoconf.h>
 
 #define MSI_DRIVER_VERSION "0.5"
 
index cd221fd0fb94b89a4c54ac3cc52da09cf7a13dee..7fa61e907e1c115b16f14936ffea65f865816f4e 100644 (file)
@@ -25,7 +25,7 @@
 #include <asm/atomic.h>
 #include <asm/io.h>
 
-#define PHANTOM_VERSION                "n0.9.7"
+#define PHANTOM_VERSION                "n0.9.8"
 
 #define PHANTOM_MAX_MINORS     8
 
@@ -456,8 +456,9 @@ static int phantom_resume(struct pci_dev *pdev)
 #endif
 
 static struct pci_device_id phantom_pci_tbl[] __devinitdata = {
-       { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
-               .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
+       { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050,
+         .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050,
+         .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);
index be4b9948c762e33b577cbd192dd836ff50c75e46..eeaaa9dce6ef62607ee510e580d647554bca8611 100644 (file)
@@ -4,7 +4,7 @@
  * block2mtd.c - create an mtd from a block device
  *
  * Copyright (C) 2001,2002     Simon Evans <spse@secret.org.uk>
- * Copyright (C) 2004-2006     Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (C) 2004-2006     Joern Engel <joern@wh.fh-wedel.de>
  *
  * Licence: GPL
  */
@@ -485,5 +485,5 @@ module_init(block2mtd_init);
 module_exit(block2mtd_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk> and others");
+MODULE_AUTHOR("Joern Engel <joern@lazybastard.org>");
 MODULE_DESCRIPTION("Emulate an MTD using a block device");
index 56cc1ca7ffd5e7d8c552c47d3d0089fe4014c2e6..180298b92a7af9a80c229a9969a30852b233fb90 100644 (file)
@@ -2,7 +2,7 @@
  * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $
  *
  * Copyright (c) ????          Jochen Schäuble <psionic@psionic.de>
- * Copyright (c) 2003-2004     Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (c) 2003-2004     Joern Engel <joern@wh.fh-wedel.de>
  *
  * Usage:
  *
@@ -299,5 +299,5 @@ module_init(init_phram);
 module_exit(cleanup_phram);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
+MODULE_AUTHOR("Joern Engel <joern@wh.fh-wedel.de>");
 MODULE_DESCRIPTION("MTD driver for physical RAM");
index d884f2be28f6574fb45f19a7cd423bee4a81a1de..2a8fde9b92f02110b0729a62754eaa2dbf7204e6 100644 (file)
@@ -4,7 +4,7 @@
  * $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $
  *
  * (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz>
- * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de>
+ * (C) 2005 Joern Engel <joern@wohnheim.fh-wedel.de>
  *
  */
 
index 36342230a6deeb79ea89c5cb011c1724b1040bca..d4843d014bc90752483711708b414cc0b804dd5d 100644 (file)
@@ -323,8 +323,8 @@ enum {
        NvRegMIIStatus = 0x180,
 #define NVREG_MIISTAT_ERROR            0x0001
 #define NVREG_MIISTAT_LINKCHANGE       0x0008
-#define NVREG_MIISTAT_MASK             0x000f
-#define NVREG_MIISTAT_MASK2            0x000f
+#define NVREG_MIISTAT_MASK_RW          0x0007
+#define NVREG_MIISTAT_MASK_ALL         0x000f
        NvRegMIIMask = 0x184,
 #define NVREG_MII_LINKCHANGE           0x0008
 
@@ -624,6 +624,9 @@ union ring_type {
 #define NV_MSI_X_VECTOR_TX    0x1
 #define NV_MSI_X_VECTOR_OTHER 0x2
 
+#define NV_RESTART_TX         0x1
+#define NV_RESTART_RX         0x2
+
 /* statistics */
 struct nv_ethtool_str {
        char name[ETH_GSTRING_LEN];
@@ -1061,7 +1064,7 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
        u32 reg;
        int retval;
 
-       writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_MASK_RW, base + NvRegMIIStatus);
 
        reg = readl(base + NvRegMIIControl);
        if (reg & NVREG_MIICTL_INUSE) {
@@ -1432,16 +1435,30 @@ static void nv_mac_reset(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
+       u32 temp1, temp2, temp3;
 
        dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name);
+
        writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
        pci_push(base);
+
+       /* save registers since they will be cleared on reset */
+       temp1 = readl(base + NvRegMacAddrA);
+       temp2 = readl(base + NvRegMacAddrB);
+       temp3 = readl(base + NvRegTransmitPoll);
+
        writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset);
        pci_push(base);
        udelay(NV_MAC_RESET_DELAY);
        writel(0, base + NvRegMacReset);
        pci_push(base);
        udelay(NV_MAC_RESET_DELAY);
+
+       /* restore saved registers */
+       writel(temp1, base + NvRegMacAddrA);
+       writel(temp2, base + NvRegMacAddrB);
+       writel(temp3, base + NvRegTransmitPoll);
+
        writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
        pci_push(base);
 }
@@ -2767,6 +2784,7 @@ static int nv_update_linkspeed(struct net_device *dev)
        int mii_status;
        int retval = 0;
        u32 control_1000, status_1000, phyreg, pause_flags, txreg;
+       u32 txrxFlags = 0;
 
        /* BMSR_LSTATUS is latched, read it twice:
         * we want the current value.
@@ -2862,6 +2880,16 @@ set_speed:
        np->duplex = newdup;
        np->linkspeed = newls;
 
+       /* The transmitter and receiver must be restarted for safe update */
+       if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_START) {
+               txrxFlags |= NV_RESTART_TX;
+               nv_stop_tx(dev);
+       }
+       if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
+               txrxFlags |= NV_RESTART_RX;
+               nv_stop_rx(dev);
+       }
+
        if (np->gigabit == PHY_GIGABIT) {
                phyreg = readl(base + NvRegRandomSeed);
                phyreg &= ~(0x3FF00);
@@ -2950,6 +2978,11 @@ set_speed:
        }
        nv_update_pause(dev, pause_flags);
 
+       if (txrxFlags & NV_RESTART_TX)
+               nv_start_tx(dev);
+       if (txrxFlags & NV_RESTART_RX)
+               nv_start_rx(dev);
+
        return retval;
 }
 
@@ -2976,7 +3009,7 @@ static void nv_link_irq(struct net_device *dev)
        u32 miistat;
 
        miistat = readl(base + NvRegMIIStatus);
-       writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_LINKCHANGE, base + NvRegMIIStatus);
        dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat);
 
        if (miistat & (NVREG_MIISTAT_LINKCHANGE))
@@ -4851,7 +4884,7 @@ static int nv_open(struct net_device *dev)
 
        writel(0, base + NvRegMIIMask);
        writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
-       writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
 
        writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
        writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
@@ -4889,7 +4922,7 @@ static int nv_open(struct net_device *dev)
 
        nv_disable_hw_interrupts(dev, np->irqmask);
        pci_push(base);
-       writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
        writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
        pci_push(base);
 
@@ -4912,7 +4945,7 @@ static int nv_open(struct net_device *dev)
        {
                u32 miistat;
                miistat = readl(base + NvRegMIIStatus);
-               writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+               writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
                dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat);
        }
        /* set linkspeed to invalid value, thus force nv_update_linkspeed
@@ -5280,7 +5313,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                phystate &= ~NVREG_ADAPTCTL_RUNNING;
                writel(phystate, base + NvRegAdapterControl);
        }
-       writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
 
        if (id->driver_data & DEV_HAS_MGMT_UNIT) {
                /* management unit running on the mac? */
index 100bf410bf5fdf655446798073c53dfed60929ff..6a647d95e6eafbba7a33547aff6af936b0a6218f 100644 (file)
@@ -127,7 +127,7 @@ int gfar_mdio_reset(struct mii_bus *bus)
        struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
        unsigned int timeout = PHY_INIT_TIMEOUT;
 
-       spin_lock_bh(&bus->mdio_lock);
+       mutex_lock(&bus->mdio_lock);
 
        /* Reset the management interface */
        gfar_write(&regs->miimcfg, MIIMCFG_RESET);
@@ -140,7 +140,7 @@ int gfar_mdio_reset(struct mii_bus *bus)
                        timeout--)
                cpu_relax();
 
-       spin_unlock_bh(&bus->mdio_lock);
+       mutex_unlock(&bus->mdio_lock);
 
        if(timeout <= 0) {
                printk(KERN_ERR "%s: The MII Bus is stuck!\n",
index 419861cbc65ecb23ae1172b6559b402bc0caa8d6..58d3bb622da6eabf5e7b5018c03fa83809019205 100644 (file)
@@ -1020,7 +1020,7 @@ static const struct ethtool_ops ops = {
        .get_link = veth_get_link,
 };
 
-static struct net_device * __init veth_probe_one(int vlan,
+static struct net_device *veth_probe_one(int vlan,
                struct vio_dev *vio_dev)
 {
        struct net_device *dev;
index a021a6e72641ef179b5e09764a9ad3fa59f2cebe..d0bf206632ca60754edbeb80977e4b359c8ff731 100644 (file)
@@ -136,8 +136,6 @@ struct ixgbe_ring {
        u16 head;
        u16 tail;
 
-       /* To protect race between sender and clean_tx_irq */
-       spinlock_t tx_lock;
 
        struct ixgbe_queue_stats stats;
 
@@ -174,7 +172,6 @@ struct ixgbe_adapter {
        struct vlan_group *vlgrp;
        u16 bd_number;
        u16 rx_buf_len;
-       atomic_t irq_sem;
        struct work_struct reset_task;
 
        /* TX */
@@ -244,6 +241,7 @@ extern const char ixgbe_driver_version[];
 
 extern int ixgbe_up(struct ixgbe_adapter *adapter);
 extern void ixgbe_down(struct ixgbe_adapter *adapter);
+extern void ixgbe_reinit_locked(struct ixgbe_adapter *adapter);
 extern void ixgbe_reset(struct ixgbe_adapter *adapter);
 extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
 extern void ixgbe_set_ethtool_ops(struct net_device *netdev);
index 36353447716ddeedbe75095a7f3ee1c96f1ebd03..a119cbd8dbb8b2aad03186d12a8e2150f3752a1b 100644 (file)
@@ -103,21 +103,41 @@ static int ixgbe_get_settings(struct net_device *netdev,
                              struct ethtool_cmd *ecmd)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 link_speed = 0;
+       bool link_up;
 
-       ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
-       ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
-       ecmd->port = PORT_FIBRE;
+       ecmd->supported = SUPPORTED_10000baseT_Full;
+       ecmd->autoneg = AUTONEG_ENABLE;
        ecmd->transceiver = XCVR_EXTERNAL;
+       if (hw->phy.media_type == ixgbe_media_type_copper) {
+               ecmd->supported |= (SUPPORTED_1000baseT_Full |
+                                   SUPPORTED_TP | SUPPORTED_Autoneg);
+
+               ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg);
+               if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
+                       ecmd->advertising |= ADVERTISED_10000baseT_Full;
+               if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
+                       ecmd->advertising |= ADVERTISED_1000baseT_Full;
+
+               ecmd->port = PORT_TP;
+       } else {
+               ecmd->supported |= SUPPORTED_FIBRE;
+               ecmd->advertising = (ADVERTISED_10000baseT_Full |
+                                    ADVERTISED_FIBRE);
+               ecmd->port = PORT_FIBRE;
+       }
 
-       if (netif_carrier_ok(adapter->netdev)) {
-               ecmd->speed = SPEED_10000;
+       adapter->hw.mac.ops.check_link(hw, &(link_speed), &link_up);
+       if (link_up) {
+               ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+                               SPEED_10000 : SPEED_1000;
                ecmd->duplex = DUPLEX_FULL;
        } else {
                ecmd->speed = -1;
                ecmd->duplex = -1;
        }
 
-       ecmd->autoneg = AUTONEG_DISABLE;
        return 0;
 }
 
@@ -125,17 +145,17 @@ static int ixgbe_set_settings(struct net_device *netdev,
                              struct ethtool_cmd *ecmd)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
 
-       if (ecmd->autoneg == AUTONEG_ENABLE ||
-           ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
-               return -EINVAL;
-
-       if (netif_running(adapter->netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_reset(adapter);
-               ixgbe_up(adapter);
-       } else {
-               ixgbe_reset(adapter);
+       switch (hw->phy.media_type) {
+       case ixgbe_media_type_fiber:
+               if ((ecmd->autoneg == AUTONEG_ENABLE) ||
+                   (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
+                       return -EINVAL;
+               /* in this case we currently only support 10Gb/FULL */
+               break;
+       default:
+               break;
        }
 
        return 0;
@@ -147,7 +167,7 @@ static void ixgbe_get_pauseparam(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
 
-       pause->autoneg = AUTONEG_DISABLE;
+       pause->autoneg = (hw->fc.type == ixgbe_fc_full ? 1 : 0);
 
        if (hw->fc.type == ixgbe_fc_rx_pause) {
                pause->rx_pause = 1;
@@ -165,10 +185,8 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
 
-       if (pause->autoneg == AUTONEG_ENABLE)
-               return -EINVAL;
-
-       if (pause->rx_pause && pause->tx_pause)
+       if ((pause->autoneg == AUTONEG_ENABLE) ||
+           (pause->rx_pause && pause->tx_pause))
                hw->fc.type = ixgbe_fc_full;
        else if (pause->rx_pause && !pause->tx_pause)
                hw->fc.type = ixgbe_fc_rx_pause;
@@ -176,15 +194,15 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
                hw->fc.type = ixgbe_fc_tx_pause;
        else if (!pause->rx_pause && !pause->tx_pause)
                hw->fc.type = ixgbe_fc_none;
+       else
+               return -EINVAL;
 
        hw->fc.original_type = hw->fc.type;
 
-       if (netif_running(adapter->netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_up(adapter);
-       } else {
+       if (netif_running(netdev))
+               ixgbe_reinit_locked(adapter);
+       else
                ixgbe_reset(adapter);
-       }
 
        return 0;
 }
@@ -203,12 +221,10 @@ static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data)
        else
                adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
 
-       if (netif_running(netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_up(adapter);
-       } else {
+       if (netif_running(netdev))
+               ixgbe_reinit_locked(adapter);
+       else
                ixgbe_reset(adapter);
-       }
 
        return 0;
 }
@@ -662,7 +678,10 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
                return 0;
        }
 
-       if (netif_running(adapter->netdev))
+       while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
+               msleep(1);
+
+       if (netif_running(netdev))
                ixgbe_down(adapter);
 
        /*
@@ -733,6 +752,7 @@ err_setup:
        if (netif_running(adapter->netdev))
                ixgbe_up(adapter);
 
+       clear_bit(__IXGBE_RESETTING, &adapter->state);
        return err;
 }
 
@@ -820,11 +840,8 @@ static int ixgbe_nway_reset(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
-       if (netif_running(netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_reset(adapter);
-               ixgbe_up(adapter);
-       }
+       if (netif_running(netdev))
+               ixgbe_reinit_locked(adapter);
 
        return 0;
 }
index 3732dd6c4b2a81fe5de5ed2883f51f082aa9b897..ead49e54f31b8fef4349d5ec551d537db5d87a27 100644 (file)
@@ -87,6 +87,25 @@ MODULE_VERSION(DRV_VERSION);
 
 #define DEFAULT_DEBUG_LEVEL_SHIFT 3
 
+static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
+{
+       u32 ctrl_ext;
+
+       /* Let firmware take over control of h/w */
+       ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+                       ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+}
+
+static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
+{
+       u32 ctrl_ext;
+
+       /* Let firmware know the driver has taken over */
+       ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+                       ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
+}
 
 #ifdef DEBUG
 /**
@@ -165,6 +184,15 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
        return false;
 }
 
+#define IXGBE_MAX_TXD_PWR      14
+#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
+                        (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
+       MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1)   /* for context */
+
 /**
  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
  * @adapter: board private structure
@@ -177,18 +205,34 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        struct ixgbe_tx_buffer *tx_buffer_info;
        unsigned int i, eop;
        bool cleaned = false;
-       int count = 0;
+       unsigned int total_tx_bytes = 0, total_tx_packets = 0;
 
        i = tx_ring->next_to_clean;
        eop = tx_ring->tx_buffer_info[i].next_to_watch;
        eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
        while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) {
-               for (cleaned = false; !cleaned;) {
+               cleaned = false;
+               while (!cleaned) {
                        tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
                        tx_buffer_info = &tx_ring->tx_buffer_info[i];
                        cleaned = (i == eop);
 
                        tx_ring->stats.bytes += tx_buffer_info->length;
+                       if (cleaned) {
+                               struct sk_buff *skb = tx_buffer_info->skb;
+#ifdef NETIF_F_TSO
+                               unsigned int segs, bytecount;
+                               segs = skb_shinfo(skb)->gso_segs ?: 1;
+                               /* multiply data chunks by size of headers */
+                               bytecount = ((segs - 1) * skb_headlen(skb)) +
+                                           skb->len;
+                               total_tx_packets += segs;
+                               total_tx_bytes += bytecount;
+#else
+                               total_tx_packets++;
+                               total_tx_bytes += skb->len;
+#endif
+                       }
                        ixgbe_unmap_and_free_tx_resource(adapter,
                                                         tx_buffer_info);
                        tx_desc->wb.status = 0;
@@ -204,29 +248,36 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
                eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
 
                /* weight of a sort for tx, avoid endless transmit cleanup */
-               if (count++ >= tx_ring->work_limit)
+               if (total_tx_packets >= tx_ring->work_limit)
                        break;
        }
 
        tx_ring->next_to_clean = i;
 
-#define TX_WAKE_THRESHOLD 32
-       spin_lock(&tx_ring->tx_lock);
-
-       if (cleaned && netif_carrier_ok(netdev) &&
-           (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD) &&
-           !test_bit(__IXGBE_DOWN, &adapter->state))
-               netif_wake_queue(netdev);
-
-       spin_unlock(&tx_ring->tx_lock);
+#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
+       if (total_tx_packets && netif_carrier_ok(netdev) &&
+           (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) {
+               /* Make sure that anybody stopping the queue after this
+                * sees the new next_to_clean.
+                */
+               smp_mb();
+               if (netif_queue_stopped(netdev) &&
+                   !test_bit(__IXGBE_DOWN, &adapter->state)) {
+                       netif_wake_queue(netdev);
+                       adapter->restart_queue++;
+               }
+       }
 
        if (adapter->detect_tx_hung)
                if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc))
                        netif_stop_queue(netdev);
 
-       if (count >= tx_ring->work_limit)
+       if (total_tx_packets >= tx_ring->work_limit)
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value);
 
+       adapter->net_stats.tx_bytes += total_tx_bytes;
+       adapter->net_stats.tx_packets += total_tx_packets;
+       cleaned = total_tx_packets ? true : false;
        return cleaned;
 }
 
@@ -255,25 +306,40 @@ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter,
        }
 }
 
+/**
+ * ixgbe_rx_checksum - indicate in skb if hw indicated a good cksum
+ * @adapter: address of board private structure
+ * @status_err: hardware indication of status of receive
+ * @skb: skb currently being received and modified
+ **/
 static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
                                         u32 status_err,
                                         struct sk_buff *skb)
 {
        skb->ip_summed = CHECKSUM_NONE;
 
-       /* Ignore Checksum bit is set */
+       /* Ignore Checksum bit is set, or rx csum disabled */
        if ((status_err & IXGBE_RXD_STAT_IXSM) ||
-                    !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
+           !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
                return;
-       /* TCP/UDP checksum error bit is set */
-       if (status_err & (IXGBE_RXDADV_ERR_TCPE | IXGBE_RXDADV_ERR_IPE)) {
-               /* let the stack verify checksum errors */
+
+       /* if IP and error */
+       if ((status_err & IXGBE_RXD_STAT_IPCS) &&
+           (status_err & IXGBE_RXDADV_ERR_IPE)) {
                adapter->hw_csum_rx_error++;
                return;
        }
+
+       if (!(status_err & IXGBE_RXD_STAT_L4CS))
+               return;
+
+       if (status_err & IXGBE_RXDADV_ERR_TCPE) {
+               adapter->hw_csum_rx_error++;
+               return;
+       }
+
        /* It must be a TCP or UDP packet with a valid checksum */
-       if (status_err & (IXGBE_RXD_STAT_L4CS | IXGBE_RXD_STAT_UDPCS))
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
        adapter->hw_csum_rx_good++;
 }
 
@@ -379,6 +445,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
        u16 hdr_info, vlan_tag;
        bool is_vlan, cleaned = false;
        int cleaned_count = 0;
+       unsigned int total_rx_bytes = 0, total_rx_packets = 0;
 
        i = rx_ring->next_to_clean;
        upper_len = 0;
@@ -458,6 +525,11 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
                }
 
                ixgbe_rx_checksum(adapter, staterr, skb);
+
+               /* probably a little skewed due to removing CRC */
+               total_rx_bytes += skb->len;
+               total_rx_packets++;
+
                skb->protocol = eth_type_trans(skb, netdev);
                ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag);
                netdev->last_rx = jiffies;
@@ -486,6 +558,9 @@ next_desc:
        if (cleaned_count)
                ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
 
+       adapter->net_stats.rx_bytes += total_rx_bytes;
+       adapter->net_stats.rx_packets += total_rx_packets;
+
        return cleaned;
 }
 
@@ -535,7 +610,9 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        mod_timer(&adapter->watchdog_timer, jiffies);
        }
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
 
        return IRQ_HANDLED;
 }
@@ -713,7 +790,6 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
        if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
                /* Disable interrupts and register for poll. The flush of the
                 * posted write is intentionally left out. */
-               atomic_inc(&adapter->irq_sem);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
                __netif_rx_schedule(netdev, &adapter->napi);
        }
@@ -801,7 +877,6 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
  **/
 static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
 {
-       atomic_inc(&adapter->irq_sem);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
        IXGBE_WRITE_FLUSH(&adapter->hw);
        synchronize_irq(adapter->pdev->irq);
@@ -813,15 +888,13 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
  **/
 static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
 {
-       if (atomic_dec_and_test(&adapter->irq_sem)) {
-               if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
-                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC,
-                                       (IXGBE_EIMS_ENABLE_MASK &
-                                        ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC)));
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
-                               IXGBE_EIMS_ENABLE_MASK);
-               IXGBE_WRITE_FLUSH(&adapter->hw);
-       }
+       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC,
+                               (IXGBE_EIMS_ENABLE_MASK &
+                                ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC)));
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
+                       IXGBE_EIMS_ENABLE_MASK);
+       IXGBE_WRITE_FLUSH(&adapter->hw);
 }
 
 /**
@@ -1040,7 +1113,8 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        u32 ctrl;
 
-       ixgbe_irq_disable(adapter);
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               ixgbe_irq_disable(adapter);
        adapter->vlgrp = grp;
 
        if (grp) {
@@ -1051,7 +1125,8 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev,
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
        }
 
-       ixgbe_irq_enable(adapter);
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               ixgbe_irq_enable(adapter);
 }
 
 static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
@@ -1066,9 +1141,13 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
-       ixgbe_irq_disable(adapter);
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               ixgbe_irq_disable(adapter);
+
        vlan_group_set_device(adapter->vlgrp, vid, NULL);
-       ixgbe_irq_enable(adapter);
+
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               ixgbe_irq_enable(adapter);
 
        /* remove VID from filter table */
        ixgbe_set_vfta(&adapter->hw, vid, 0, false);
@@ -1170,6 +1249,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
        u32 txdctl, rxdctl, mhadd;
        int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
 
+       ixgbe_get_hw_control(adapter);
+
        if (adapter->flags & (IXGBE_FLAG_MSIX_ENABLED |
                              IXGBE_FLAG_MSI_ENABLED)) {
                if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
@@ -1224,6 +1305,16 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
        return 0;
 }
 
+void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
+{
+       WARN_ON(in_interrupt());
+       while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
+               msleep(1);
+       ixgbe_down(adapter);
+       ixgbe_up(adapter);
+       clear_bit(__IXGBE_RESETTING, &adapter->state);
+}
+
 int ixgbe_up(struct ixgbe_adapter *adapter)
 {
        /* hardware has been reset, we need to reload some things */
@@ -1408,7 +1499,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        msleep(10);
 
        napi_disable(&adapter->napi);
-       atomic_set(&adapter->irq_sem, 0);
 
        ixgbe_irq_disable(adapter);
 
@@ -1447,6 +1537,8 @@ static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
        pci_enable_wake(pdev, PCI_D3hot, 0);
        pci_enable_wake(pdev, PCI_D3cold, 0);
 
+       ixgbe_release_hw_control(adapter);
+
        pci_disable_device(pdev);
 
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -1481,7 +1573,8 @@ static int ixgbe_clean(struct napi_struct *napi, int budget)
        /* If budget not fully consumed, exit the polling mode */
        if (work_done < budget) {
                netif_rx_complete(netdev, napi);
-               ixgbe_irq_enable(adapter);
+               if (!test_bit(__IXGBE_DOWN, &adapter->state))
+                       ixgbe_irq_enable(adapter);
        }
 
        return work_done;
@@ -1506,8 +1599,7 @@ static void ixgbe_reset_task(struct work_struct *work)
 
        adapter->tx_timeout_count++;
 
-       ixgbe_down(adapter);
-       ixgbe_up(adapter);
+       ixgbe_reinit_locked(adapter);
 }
 
 /**
@@ -1590,7 +1682,6 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
                return -ENOMEM;
        }
 
-       atomic_set(&adapter->irq_sem, 1);
        set_bit(__IXGBE_DOWN, &adapter->state);
 
        return 0;
@@ -1634,7 +1725,6 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
        txdr->next_to_use = 0;
        txdr->next_to_clean = 0;
        txdr->work_limit = txdr->count;
-       spin_lock_init(&txdr->tx_lock);
 
        return 0;
 }
@@ -1828,10 +1918,8 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
 
        netdev->mtu = new_mtu;
 
-       if (netif_running(netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_up(adapter);
-       }
+       if (netif_running(netdev))
+               ixgbe_reinit_locked(adapter);
 
        return 0;
 }
@@ -1852,14 +1940,8 @@ static int ixgbe_open(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        int err;
-       u32 ctrl_ext;
        u32 num_rx_queues = adapter->num_rx_queues;
 
-       /* Let firmware know the driver has taken over */
-       ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
-                       ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
-
 try_intr_reinit:
        /* allocate transmit descriptors */
        err = ixgbe_setup_all_tx_resources(adapter);
@@ -1910,6 +1992,7 @@ try_intr_reinit:
        return 0;
 
 err_up:
+       ixgbe_release_hw_control(adapter);
        ixgbe_free_irq(adapter);
 err_req_irq:
        ixgbe_free_all_rx_resources(adapter);
@@ -1935,7 +2018,6 @@ err_setup_tx:
 static int ixgbe_close(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       u32 ctrl_ext;
 
        ixgbe_down(adapter);
        ixgbe_free_irq(adapter);
@@ -1943,9 +2025,7 @@ static int ixgbe_close(struct net_device *netdev)
        ixgbe_free_all_tx_resources(adapter);
        ixgbe_free_all_rx_resources(adapter);
 
-       ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
-                       ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+       ixgbe_release_hw_control(adapter);
 
        return 0;
 }
@@ -1957,22 +2037,26 @@ static int ixgbe_close(struct net_device *netdev)
 void ixgbe_update_stats(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
-       u64 good_rx, missed_rx, bprc;
+       u64 total_mpc = 0;
+       u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot;
 
        adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
-       good_rx = IXGBE_READ_REG(hw, IXGBE_GPRC);
-       missed_rx = IXGBE_READ_REG(hw, IXGBE_MPC(0));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(1));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(2));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(3));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(4));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(5));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(6));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(7));
-       adapter->stats.gprc += (good_rx - missed_rx);
-
-       adapter->stats.mpc[0] += missed_rx;
+       for (i = 0; i < 8; i++) {
+               /* for packet buffers not used, the register should read 0 */
+               mpc = IXGBE_READ_REG(hw, IXGBE_MPC(i));
+               missed_rx += mpc;
+               adapter->stats.mpc[i] += mpc;
+               total_mpc += adapter->stats.mpc[i];
+               adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+       }
+       adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
+       /* work around hardware counting issue */
+       adapter->stats.gprc -= missed_rx;
+
+       /* 82598 hardware only has a 32 bit counter in the high register */
        adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+       adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+       adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
        bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
        adapter->stats.bprc += bprc;
        adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
@@ -1984,35 +2068,37 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
        adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
        adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
        adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
-
        adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
        adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
-       adapter->stats.lxontxc += IXGBE_READ_REG(hw, IXGBE_LXONTXC);
        adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
-       adapter->stats.lxofftxc += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+       lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
+       adapter->stats.lxontxc += lxon;
+       lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+       adapter->stats.lxofftxc += lxoff;
        adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
        adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
-       adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
-       adapter->stats.rnbc[0] += IXGBE_READ_REG(hw, IXGBE_RNBC(0));
+       adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
+       /*
+        * 82598 errata - tx of flow control packets is included in tx counters
+        */
+       xon_off_tot = lxon + lxoff;
+       adapter->stats.gptc -= xon_off_tot;
+       adapter->stats.mptc -= xon_off_tot;
+       adapter->stats.gotc -= (xon_off_tot * (ETH_ZLEN + ETH_FCS_LEN));
        adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
        adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
        adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
-       adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
        adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
        adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
+       adapter->stats.ptc64 -= xon_off_tot;
        adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
        adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
        adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
        adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
        adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
-       adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
        adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
 
        /* Fill out the OS statistics structure */
-       adapter->net_stats.rx_packets = adapter->stats.gprc;
-       adapter->net_stats.tx_packets = adapter->stats.gptc;
-       adapter->net_stats.rx_bytes = adapter->stats.gorc;
-       adapter->net_stats.tx_bytes = adapter->stats.gotc;
        adapter->net_stats.multicast = adapter->stats.mprc;
 
        /* Rx Errors */
@@ -2021,8 +2107,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
        adapter->net_stats.rx_dropped = 0;
        adapter->net_stats.rx_length_errors = adapter->stats.rlec;
        adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
-       adapter->net_stats.rx_missed_errors = adapter->stats.mpc[0];
-
+       adapter->net_stats.rx_missed_errors = total_mpc;
 }
 
 /**
@@ -2076,15 +2161,6 @@ static void ixgbe_watchdog(unsigned long data)
                          round_jiffies(jiffies + 2 * HZ));
 }
 
-#define IXGBE_MAX_TXD_PWR      14
-#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
-
-/* Tx Descriptors needed, worst case */
-#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
-                        (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
-#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
-       MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1)   /* for context */
-
 static int ixgbe_tso(struct ixgbe_adapter *adapter,
                         struct ixgbe_ring *tx_ring, struct sk_buff *skb,
                         u32 tx_flags, u8 *hdr_len)
@@ -2356,6 +2432,37 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
        writel(i, adapter->hw.hw_addr + tx_ring->tail);
 }
 
+static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
+                                struct ixgbe_ring *tx_ring, int size)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+       netif_stop_queue(netdev);
+       /* Herbert's original patch had:
+        *  smp_mb__after_netif_stop_queue();
+        * but since that doesn't exist yet, just open code it. */
+       smp_mb();
+
+       /* We need to check again in a case another CPU has just
+        * made room available. */
+       if (likely(IXGBE_DESC_UNUSED(tx_ring) < size))
+               return -EBUSY;
+
+       /* A reprieve! - use start_queue because it doesn't call schedule */
+       netif_wake_queue(netdev);
+       ++adapter->restart_queue;
+       return 0;
+}
+
+static int ixgbe_maybe_stop_tx(struct net_device *netdev,
+                              struct ixgbe_ring *tx_ring, int size)
+{
+       if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size))
+               return 0;
+       return __ixgbe_maybe_stop_tx(netdev, tx_ring, size);
+}
+
+
 static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -2363,7 +2470,6 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        unsigned int len = skb->len;
        unsigned int first;
        unsigned int tx_flags = 0;
-       unsigned long flags = 0;
        u8 hdr_len;
        int tso;
        unsigned int mss = 0;
@@ -2389,14 +2495,10 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        for (f = 0; f < nr_frags; f++)
                count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
 
-       spin_lock_irqsave(&tx_ring->tx_lock, flags);
-       if (IXGBE_DESC_UNUSED(tx_ring) < (count + 2)) {
+       if (ixgbe_maybe_stop_tx(netdev, tx_ring, count)) {
                adapter->tx_busy++;
-               netif_stop_queue(netdev);
-               spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
                return NETDEV_TX_BUSY;
        }
-       spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
        if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
                tx_flags |= IXGBE_TX_FLAGS_VLAN;
                tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT);
@@ -2423,11 +2525,7 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        netdev->trans_start = jiffies;
 
-       spin_lock_irqsave(&tx_ring->tx_lock, flags);
-       /* Make sure there is space in the ring for the next send. */
-       if (IXGBE_DESC_UNUSED(tx_ring) < DESC_NEEDED)
-               netif_stop_queue(netdev);
-       spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+       ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
 
        return NETDEV_TX_OK;
 }
@@ -2697,6 +2795,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        return 0;
 
 err_register:
+       ixgbe_release_hw_control(adapter);
 err_hw_init:
 err_sw_init:
 err_eeprom:
@@ -2732,6 +2831,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
 
        unregister_netdev(netdev);
 
+       ixgbe_release_hw_control(adapter);
+
        kfree(adapter->tx_ring);
        kfree(adapter->rx_ring);
 
index 651c2699d5e1cdf0eeb914ac21c89a19ce7961f7..b528ce77c4069997d67ffaac2e0c00b1b6f5d383 100644 (file)
@@ -1652,6 +1652,11 @@ static void eth_tx_fill_frag_descs(struct mv643xx_private *mp,
        }
 }
 
+static inline __be16 sum16_as_be(__sum16 sum)
+{
+       return (__force __be16)sum;
+}
+
 /**
  * eth_tx_submit_descs_for_skb - submit data from an skb to the tx hw
  *
@@ -1689,7 +1694,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp,
        desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               BUG_ON(skb->protocol != ETH_P_IP);
+               BUG_ON(skb->protocol != htons(ETH_P_IP));
 
                cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
                           ETH_GEN_IP_V_4_CHECKSUM  |
@@ -1698,10 +1703,10 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp,
                switch (ip_hdr(skb)->protocol) {
                case IPPROTO_UDP:
                        cmd_sts |= ETH_UDP_FRAME;
-                       desc->l4i_chk = udp_hdr(skb)->check;
+                       desc->l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check));
                        break;
                case IPPROTO_TCP:
-                       desc->l4i_chk = tcp_hdr(skb)->check;
+                       desc->l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check));
                        break;
                default:
                        BUG();
index 1b51bb668d39ac2fb6ecb8b44a3797f06556eea3..5aa0a80896945c994ec574e0c5cb8d035eda5466 100644 (file)
@@ -2468,9 +2468,10 @@ static int __init pppol2tp_init(void)
 
 out:
        return err;
-
+#ifdef CONFIG_PROC_FS
 out_unregister_pppox_proto:
        unregister_pppox_proto(PX_PROTO_OL2TP);
+#endif
 out_unregister_pppol2tp_proto:
        proto_unregister(&pppol2tp_sk_proto);
        goto out;
index dc062367a1c8b515138b7023921d81e31eac82d4..9a6295909e43c318d4fa4da46995d2121e362920 100644 (file)
@@ -857,7 +857,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
        sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
 
        /* On chips without ram buffer, pause is controled by MAC level */
-       if (sky2_read8(hw, B2_E_0) == 0) {
+       if (!(hw->flags & SKY2_HW_RAM_BUFFER)) {
                sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
                sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
 
@@ -1194,7 +1194,7 @@ static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2)
        struct sk_buff *skb;
        int i;
 
-       if (sky2->hw->flags & SKY2_HW_FIFO_HANG_CHECK) {
+       if (sky2->hw->flags & SKY2_HW_RAM_BUFFER) {
                unsigned char *start;
                /*
                 * Workaround for a bug in FIFO that cause hang
@@ -1387,6 +1387,7 @@ static int sky2_up(struct net_device *dev)
        if (ramsize > 0) {
                u32 rxspace;
 
+               hw->flags |= SKY2_HW_RAM_BUFFER;
                pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize);
                if (ramsize < 16)
                        rxspace = ramsize / 2;
@@ -2026,7 +2027,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
 
        synchronize_irq(hw->pdev->irq);
 
-       if (sky2_read8(hw, B2_E_0) == 0)
+       if (!(hw->flags & SKY2_HW_RAM_BUFFER))
                sky2_set_tx_stfwd(hw, port);
 
        ctl = gma_read16(hw, port, GM_GP_CTRL);
@@ -2566,7 +2567,7 @@ static void sky2_watchdog(unsigned long arg)
                        ++active;
 
                        /* For chips with Rx FIFO, check if stuck */
-                       if ((hw->flags & SKY2_HW_FIFO_HANG_CHECK) &&
+                       if ((hw->flags & SKY2_HW_RAM_BUFFER) &&
                             sky2_rx_hung(dev)) {
                                pr_info(PFX "%s: receiver hang detected\n",
                                        dev->name);
@@ -2722,11 +2723,7 @@ static int __devinit sky2_init(struct sky2_hw *hw)
 
        switch(hw->chip_id) {
        case CHIP_ID_YUKON_XL:
-               hw->flags = SKY2_HW_GIGABIT
-                       | SKY2_HW_NEWER_PHY;
-               if (hw->chip_rev < 3)
-                       hw->flags |= SKY2_HW_FIFO_HANG_CHECK;
-
+               hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY;
                break;
 
        case CHIP_ID_YUKON_EC_U:
@@ -2752,7 +2749,7 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                        dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n");
                        return -EOPNOTSUPP;
                }
-               hw->flags = SKY2_HW_GIGABIT | SKY2_HW_FIFO_HANG_CHECK;
+               hw->flags = SKY2_HW_GIGABIT;
                break;
 
        case CHIP_ID_YUKON_FE:
index 2bced1a0898f45a1b08bb60d941c938619d7c7e0..5ab5c1c7c5aa76ed30d8c6850b09192afac5d6db 100644 (file)
@@ -2045,7 +2045,7 @@ struct sky2_hw {
 #define SKY2_HW_FIBRE_PHY      0x00000002
 #define SKY2_HW_GIGABIT                0x00000004
 #define SKY2_HW_NEWER_PHY      0x00000008
-#define SKY2_HW_FIFO_HANG_CHECK        0x00000010
+#define SKY2_HW_RAM_BUFFER     0x00000010
 #define SKY2_HW_NEW_LE         0x00000020      /* new LSOv2 format */
 #define SKY2_HW_AUTO_TX_SUM    0x00000040      /* new IP decode for Tx */
 #define SKY2_HW_ADV_POWER_CTL  0x00000080      /* additional PHY power regs */
index c99ce74a7aff7251c3821314fab0e43be38ffd2f..3af5b92b48c8f1c18ba24b75df46e44ed04959e5 100644 (file)
@@ -465,7 +465,7 @@ static struct pci_driver tlan_driver = {
 
 static int __init tlan_probe(void)
 {
-       static int      pad_allocated;
+       int rc = -ENODEV;
 
        printk(KERN_INFO "%s", tlan_banner);
 
@@ -473,17 +473,22 @@ static int __init tlan_probe(void)
 
        if (TLanPadBuffer == NULL) {
                printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n");
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto err_out;
        }
 
        memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE);
-       pad_allocated = 1;
 
        TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n");
 
        /* Use new style PCI probing. Now the kernel will
           do most of this for us */
-       pci_register_driver(&tlan_driver);
+       rc = pci_register_driver(&tlan_driver);
+
+       if (rc != 0) {
+               printk(KERN_ERR "TLAN: Could not register pci driver.\n");
+               goto err_out_pci_free;
+       }
 
        TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n");
        TLan_EisaProbe();
@@ -493,11 +498,17 @@ static int __init tlan_probe(void)
                 tlan_have_pci, tlan_have_eisa);
 
        if (TLanDevicesInstalled == 0) {
-               pci_unregister_driver(&tlan_driver);
-               pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
-               return -ENODEV;
+               rc = -ENODEV;
+               goto  err_out_pci_unreg;
        }
        return 0;
+
+err_out_pci_unreg:
+       pci_unregister_driver(&tlan_driver);
+err_out_pci_free:
+       pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
+err_out:
+       return rc;
 }
 
 
index 8fc7274642eb41f851e78af59d66fb5468954090..6b93d016911650e0ef778ffeaf3dd9c06e370069 100644 (file)
@@ -441,7 +441,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&card->lock,flags);
        trigger_transmit(card);
 
-       return -EIO;
+       return NETDEV_TX_BUSY;
 }
 
 
index e3ba14a19915d0ab5b01837c9429339761c216eb..c69e654d539fcaae8df42cd7065af9e857c8d292 100644 (file)
@@ -109,7 +109,7 @@ int uec_mdio_reset(struct mii_bus *bus)
        struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
        unsigned int timeout = PHY_INIT_TIMEOUT;
 
-       spin_lock_bh(&bus->mdio_lock);
+       mutex_lock(&bus->mdio_lock);
 
        /* Reset the management interface */
        out_be32(&regs->miimcfg, MIIMCFG_RESET_MANAGEMENT);
@@ -121,7 +121,7 @@ int uec_mdio_reset(struct mii_bus *bus)
        while ((in_be32(&regs->miimind) & MIIMIND_BUSY) && timeout--)
                cpu_relax();
 
-       spin_unlock_bh(&bus->mdio_lock);
+       mutex_unlock(&bus->mdio_lock);
 
        if (timeout <= 0) {
                printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name);
index e66de0c12fc10e1455e4137f8f68271ca44505b5..fdc23678117bdd31157a13c6d428d2c1951dc778 100644 (file)
@@ -302,10 +302,12 @@ static int virtnet_open(struct net_device *dev)
 
        /* If all buffers were filled by other side before we napi_enabled, we
         * won't get another interrupt, so process any outstanding packets
-        * now.  virtnet_poll wants re-enable the queue, so we disable here. */
-       vi->rvq->vq_ops->disable_cb(vi->rvq);
-       netif_rx_schedule(vi->dev, &vi->napi);
-
+        * now.  virtnet_poll wants re-enable the queue, so we disable here.
+        * We synchronize against interrupts via NAPI_STATE_SCHED */
+       if (netif_rx_schedule_prep(dev, &vi->napi)) {
+               vi->rvq->vq_ops->disable_cb(vi->rvq);
+               __netif_rx_schedule(dev, &vi->napi);
+       }
        return 0;
 }
 
index d553e6f328513a56f633bf35d2e562c5d979f08f..39951d0c34d6598b44a9d701fe3c5f1df2df5ceb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Generic HDLC support routines for Linux
  *
- * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2008 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License
@@ -39,7 +39,7 @@
 #include <net/net_namespace.h>
 
 
-static const char* version = "HDLC support module revision 1.21";
+static const char* version = "HDLC support module revision 1.22";
 
 #undef DEBUG_LINK
 
@@ -66,19 +66,15 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
 static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
                    struct packet_type *p, struct net_device *orig_dev)
 {
-       struct hdlc_device_desc *desc = dev_to_desc(dev);
+       struct hdlc_device *hdlc = dev_to_hdlc(dev);
 
        if (dev->nd_net != &init_net) {
                kfree_skb(skb);
                return 0;
        }
 
-       if (desc->netif_rx)
-               return desc->netif_rx(skb);
-
-       desc->stats.rx_dropped++; /* Shouldn't happen */
-       dev_kfree_skb(skb);
-       return NET_RX_DROP;
+       BUG_ON(!hdlc->proto->netif_rx);
+       return hdlc->proto->netif_rx(skb);
 }
 
 
@@ -87,7 +83,7 @@ static inline void hdlc_proto_start(struct net_device *dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
        if (hdlc->proto->start)
-               return hdlc->proto->start(dev);
+               hdlc->proto->start(dev);
 }
 
 
@@ -96,7 +92,7 @@ static inline void hdlc_proto_stop(struct net_device *dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
        if (hdlc->proto->stop)
-               return hdlc->proto->stop(dev);
+               hdlc->proto->stop(dev);
 }
 
 
@@ -263,8 +259,7 @@ static void hdlc_setup(struct net_device *dev)
 struct net_device *alloc_hdlcdev(void *priv)
 {
        struct net_device *dev;
-       dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
-                          sizeof(hdlc_device), "hdlc%d", hdlc_setup);
+       dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d", hdlc_setup);
        if (dev)
                dev_to_hdlc(dev)->priv = priv;
        return dev;
@@ -281,7 +276,7 @@ void unregister_hdlc_device(struct net_device *dev)
 
 
 int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
-                        int (*rx)(struct sk_buff *skb), size_t size)
+                        size_t size)
 {
        detach_hdlc_protocol(dev);
 
@@ -297,7 +292,6 @@ int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
                        return -ENOBUFS;
                }
        dev_to_hdlc(dev)->proto = proto;
-       dev_to_desc(dev)->netif_rx = rx;
        return 0;
 }
 
index 038a6e748bbffdcfdd39bca117709f65f5510bb0..7133c688cf20569e71aed38b83ca3db4bcd59896 100644 (file)
@@ -250,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb)
        return NET_RX_DROP;
 
  rx_error:
-       dev_to_desc(dev)->stats.rx_errors++; /* Mark error */
+       dev_to_hdlc(dev)->stats.rx_errors++; /* Mark error */
        dev_kfree_skb_any(skb);
        return NET_RX_DROP;
 }
@@ -314,6 +314,7 @@ static struct hdlc_proto proto = {
        .stop           = cisco_stop,
        .type_trans     = cisco_type_trans,
        .ioctl          = cisco_ioctl,
+       .netif_rx       = cisco_rx,
        .module         = THIS_MODULE,
 };
 
@@ -360,7 +361,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               result = attach_hdlc_protocol(dev, &proto, cisco_rx,
+               result = attach_hdlc_protocol(dev, &proto,
                                              sizeof(struct cisco_state));
                if (result)
                        return result;
index 071a64cacd5c29cdedfc959c922bea885a7a7cc2..c4ab0326f91103b03dcd01dd7b1a153101ef4ea9 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/pkt_sched.h>
-#include <linux/random.h>
 #include <linux/inetdevice.h>
 #include <linux/lapb.h>
 #include <linux/rtnetlink.h>
@@ -136,6 +135,10 @@ typedef struct pvc_device_struct {
        }state;
 }pvc_device;
 
+struct pvc_desc {
+       struct net_device_stats stats;
+       pvc_device *pvc;
+};
 
 struct frad_state {
        fr_proto settings;
@@ -171,17 +174,20 @@ static inline void dlci_to_q922(u8 *hdr, u16 dlci)
 }
 
 
-static inline struct frad_state * state(hdlc_device *hdlc)
+static inline struct frad_state* state(hdlc_device *hdlc)
 {
        return(struct frad_state *)(hdlc->state);
 }
 
-
-static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+static inline struct pvc_desc* pvcdev_to_desc(struct net_device *dev)
 {
        return dev->priv;
 }
 
+static inline struct net_device_stats* pvc_get_stats(struct net_device *dev)
+{
+       return &pvcdev_to_desc(dev)->stats;
+}
 
 static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
 {
@@ -351,7 +357,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
 
 static int pvc_open(struct net_device *dev)
 {
-       pvc_device *pvc = dev_to_pvc(dev);
+       pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
 
        if ((pvc->frad->flags & IFF_UP) == 0)
                return -EIO;  /* Frad must be UP in order to activate PVC */
@@ -371,7 +377,7 @@ static int pvc_open(struct net_device *dev)
 
 static int pvc_close(struct net_device *dev)
 {
-       pvc_device *pvc = dev_to_pvc(dev);
+       pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
 
        if (--pvc->open_count == 0) {
                hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
@@ -390,7 +396,7 @@ static int pvc_close(struct net_device *dev)
 
 static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-       pvc_device *pvc = dev_to_pvc(dev);
+       pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
        fr_proto_pvc_info info;
 
        if (ifr->ifr_settings.type == IF_GET_PROTO) {
@@ -416,17 +422,9 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EINVAL;
 }
 
-
-static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
-{
-       return &dev_to_desc(dev)->stats;
-}
-
-
-
 static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       pvc_device *pvc = dev_to_pvc(dev);
+       pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
        struct net_device_stats *stats = pvc_get_stats(dev);
 
        if (pvc->state.active) {
@@ -957,7 +955,7 @@ static int fr_rx(struct sk_buff *skb)
 
 
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
-               dev_to_desc(frad)->stats.rx_dropped++;
+               dev_to_hdlc(frad)->stats.rx_dropped++;
                return NET_RX_DROP;
        }
 
@@ -1018,7 +1016,7 @@ static int fr_rx(struct sk_buff *skb)
        }
 
  rx_error:
-       dev_to_desc(frad)->stats.rx_errors++; /* Mark error */
+       dev_to_hdlc(frad)->stats.rx_errors++; /* Mark error */
        dev_kfree_skb_any(skb);
        return NET_RX_DROP;
 }
@@ -1109,11 +1107,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
        used = pvc_is_used(pvc);
 
        if (type == ARPHRD_ETHER)
-               dev = alloc_netdev(sizeof(struct net_device_stats),
-                                  "pvceth%d", ether_setup);
+               dev = alloc_netdev(sizeof(struct pvc_desc), "pvceth%d",
+                                  ether_setup);
        else
-               dev = alloc_netdev(sizeof(struct net_device_stats),
-                                  "pvc%d", pvc_setup);
+               dev = alloc_netdev(sizeof(struct pvc_desc), "pvc%d", pvc_setup);
 
        if (!dev) {
                printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
@@ -1122,10 +1119,9 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
                return -ENOBUFS;
        }
 
-       if (type == ARPHRD_ETHER) {
-               memcpy(dev->dev_addr, "\x00\x01", 2);
-                get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
-       } else {
+       if (type == ARPHRD_ETHER)
+               random_ether_addr(dev->dev_addr);
+       else {
                *(__be16*)dev->dev_addr = htons(dlci);
                dlci_to_q922(dev->broadcast, dlci);
        }
@@ -1137,7 +1133,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
        dev->change_mtu = pvc_change_mtu;
        dev->mtu = HDLC_MAX_MTU;
        dev->tx_queue_len = 0;
-       dev->priv = pvc;
+       pvcdev_to_desc(dev)->pvc = pvc;
 
        result = dev_alloc_name(dev, dev->name);
        if (result < 0) {
@@ -1219,6 +1215,7 @@ static struct hdlc_proto proto = {
        .stop           = fr_stop,
        .detach         = fr_destroy,
        .ioctl          = fr_ioctl,
+       .netif_rx       = fr_rx,
        .module         = THIS_MODULE,
 };
 
@@ -1277,7 +1274,7 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
                        return result;
 
                if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */
-                       result = attach_hdlc_protocol(dev, &proto, fr_rx,
+                       result = attach_hdlc_protocol(dev, &proto,
                                                      sizeof(struct frad_state));
                        if (result)
                                return result;
index 519e1550e2e785fb99349b676f13a83bb497336e..10396d9686f4f7a5413d647772ff947831bedf52 100644 (file)
@@ -122,7 +122,7 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               result = attach_hdlc_protocol(dev, &proto, NULL,
+               result = attach_hdlc_protocol(dev, &proto,
                                              sizeof(struct ppp_state));
                if (result)
                        return result;
index e23bc6656267401270488809d0a73d886203adb8..bbbb819d764cbc068f4fb9646cba63c8c2b226f6 100644 (file)
@@ -82,7 +82,7 @@ static int raw_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               result = attach_hdlc_protocol(dev, &proto, NULL,
+               result = attach_hdlc_protocol(dev, &proto,
                                              sizeof(raw_hdlc_proto));
                if (result)
                        return result;
index 8895394e60062071fc986a7b0acd4218fdbe3ef4..d20c685f67111281699dcc1449b366dc22fb04e9 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/pkt_sched.h>
-#include <linux/random.h>
 #include <linux/inetdevice.h>
 #include <linux/lapb.h>
 #include <linux/rtnetlink.h>
@@ -96,7 +95,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               result = attach_hdlc_protocol(dev, &proto, NULL,
+               result = attach_hdlc_protocol(dev, &proto,
                                              sizeof(raw_hdlc_proto));
                if (result)
                        return result;
@@ -107,8 +106,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
                ether_setup(dev);
                dev->change_mtu = old_ch_mtu;
                dev->tx_queue_len = old_qlen;
-               memcpy(dev->dev_addr, "\x00\x01", 2);
-                get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
+               random_ether_addr(dev->dev_addr);
                netif_dormant_off(dev);
                return 0;
        }
index cd7b22f50edc562d9fa9f35bf809656fc834227b..c15cc11e399bed72fac105edbb1270469c9e8eb5 100644 (file)
@@ -164,17 +164,17 @@ static void x25_close(struct net_device *dev)
 
 static int x25_rx(struct sk_buff *skb)
 {
-       struct hdlc_device_desc *desc = dev_to_desc(skb->dev);
+       struct hdlc_device *hdlc = dev_to_hdlc(skb->dev);
 
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
-               desc->stats.rx_dropped++;
+               hdlc->stats.rx_dropped++;
                return NET_RX_DROP;
        }
 
        if (lapb_data_received(skb->dev, skb) == LAPB_OK)
                return NET_RX_SUCCESS;
 
-       desc->stats.rx_errors++;
+       hdlc->stats.rx_errors++;
        dev_kfree_skb_any(skb);
        return NET_RX_DROP;
 }
@@ -184,6 +184,7 @@ static struct hdlc_proto proto = {
        .open           = x25_open,
        .close          = x25_close,
        .ioctl          = x25_ioctl,
+       .netif_rx       = x25_rx,
        .module         = THIS_MODULE,
 };
 
@@ -211,8 +212,7 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               if ((result = attach_hdlc_protocol(dev, &proto,
-                                                  x25_rx, 0)) != 0)
+               if ((result = attach_hdlc_protocol(dev, &proto, 0)))
                        return result;
                dev->hard_start_xmit = x25_xmit;
                dev->type = ARPHRD_X25;
index 8a708b77925df438ab5eb959b15edd025da31c96..3dfb28a34be9f8259c75bf5490a703cd88303a02 100644 (file)
@@ -337,7 +337,7 @@ static inline int txring_to_priority(struct b43_dmaring *ring)
        return idx_to_prio[index];
 }
 
-u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
+static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
 {
        static const u16 map64[] = {
                B43_MMIO_DMA64_BASE0,
@@ -356,7 +356,7 @@ u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
                B43_MMIO_DMA32_BASE5,
        };
 
-       if (dma64bit) {
+       if (type == B43_DMA_64BIT) {
                B43_WARN_ON(!(controller_idx >= 0 &&
                              controller_idx < ARRAY_SIZE(map64)));
                return map64[controller_idx];
@@ -437,7 +437,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
         * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
         * which accounts for the GFP_DMA flag below.
         */
-       if (ring->dma64)
+       if (ring->type == B43_DMA_64BIT)
                flags |= GFP_DMA;
        ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
                                            &(ring->dmabase), flags);
@@ -459,7 +459,8 @@ static void free_ringmemory(struct b43_dmaring *ring)
 }
 
 /* Reset the RX DMA channel */
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+static int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base,
+                                     enum b43_dmatype type)
 {
        int i;
        u32 value;
@@ -467,12 +468,13 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 
        might_sleep();
 
-       offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
+       offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
        b43_write32(dev, mmio_base + offset, 0);
        for (i = 0; i < 10; i++) {
-               offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
+               offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXSTATUS :
+                                                  B43_DMA32_RXSTATUS;
                value = b43_read32(dev, mmio_base + offset);
-               if (dma64) {
+               if (type == B43_DMA_64BIT) {
                        value &= B43_DMA64_RXSTAT;
                        if (value == B43_DMA64_RXSTAT_DISABLED) {
                                i = -1;
@@ -496,7 +498,8 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 }
 
 /* Reset the TX DMA channel */
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
+                                     enum b43_dmatype type)
 {
        int i;
        u32 value;
@@ -505,9 +508,10 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
        might_sleep();
 
        for (i = 0; i < 10; i++) {
-               offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+               offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+                                                  B43_DMA32_TXSTATUS;
                value = b43_read32(dev, mmio_base + offset);
-               if (dma64) {
+               if (type == B43_DMA_64BIT) {
                        value &= B43_DMA64_TXSTAT;
                        if (value == B43_DMA64_TXSTAT_DISABLED ||
                            value == B43_DMA64_TXSTAT_IDLEWAIT ||
@@ -522,12 +526,13 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
                }
                msleep(1);
        }
-       offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
+       offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
        b43_write32(dev, mmio_base + offset, 0);
        for (i = 0; i < 10; i++) {
-               offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+               offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+                                                  B43_DMA32_TXSTATUS;
                value = b43_read32(dev, mmio_base + offset);
-               if (dma64) {
+               if (type == B43_DMA_64BIT) {
                        value &= B43_DMA64_TXSTAT;
                        if (value == B43_DMA64_TXSTAT_DISABLED) {
                                i = -1;
@@ -552,6 +557,33 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
        return 0;
 }
 
+/* Check if a DMA mapping address is invalid. */
+static bool b43_dma_mapping_error(struct b43_dmaring *ring,
+                                 dma_addr_t addr,
+                                 size_t buffersize)
+{
+       if (unlikely(dma_mapping_error(addr)))
+               return 1;
+
+       switch (ring->type) {
+       case B43_DMA_30BIT:
+               if ((u64)addr + buffersize > (1ULL << 30))
+                       return 1;
+               break;
+       case B43_DMA_32BIT:
+               if ((u64)addr + buffersize > (1ULL << 32))
+                       return 1;
+               break;
+       case B43_DMA_64BIT:
+               /* Currently we can't have addresses beyond
+                * 64bit in the kernel. */
+               break;
+       }
+
+       /* The address is OK. */
+       return 0;
+}
+
 static int setup_rx_descbuffer(struct b43_dmaring *ring,
                               struct b43_dmadesc_generic *desc,
                               struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
@@ -567,7 +599,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
        if (unlikely(!skb))
                return -ENOMEM;
        dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
-       if (dma_mapping_error(dmaaddr)) {
+       if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
                /* ugh. try to realloc in zone_dma */
                gfp_flags |= GFP_DMA;
 
@@ -580,7 +612,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
                                         ring->rx_buffersize, 0);
        }
 
-       if (dma_mapping_error(dmaaddr)) {
+       if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
                dev_kfree_skb_any(skb);
                return -EIO;
        }
@@ -645,7 +677,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
        u32 trans = ssb_dma_translation(ring->dev->dev);
 
        if (ring->tx) {
-               if (ring->dma64) {
+               if (ring->type == B43_DMA_64BIT) {
                        u64 ringbase = (u64) (ring->dmabase);
 
                        addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -677,7 +709,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
                err = alloc_initial_descbuffers(ring);
                if (err)
                        goto out;
-               if (ring->dma64) {
+               if (ring->type == B43_DMA_64BIT) {
                        u64 ringbase = (u64) (ring->dmabase);
 
                        addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -722,16 +754,16 @@ static void dmacontroller_cleanup(struct b43_dmaring *ring)
 {
        if (ring->tx) {
                b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
-                                          ring->dma64);
-               if (ring->dma64) {
+                                          ring->type);
+               if (ring->type == B43_DMA_64BIT) {
                        b43_dma_write(ring, B43_DMA64_TXRINGLO, 0);
                        b43_dma_write(ring, B43_DMA64_TXRINGHI, 0);
                } else
                        b43_dma_write(ring, B43_DMA32_TXRING, 0);
        } else {
                b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
-                                          ring->dma64);
-               if (ring->dma64) {
+                                          ring->type);
+               if (ring->type == B43_DMA_64BIT) {
                        b43_dma_write(ring, B43_DMA64_RXRINGLO, 0);
                        b43_dma_write(ring, B43_DMA64_RXRINGHI, 0);
                } else
@@ -786,7 +818,8 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
 static
 struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                                      int controller_index,
-                                     int for_tx, int dma64)
+                                     int for_tx,
+                                     enum b43_dmatype type)
 {
        struct b43_dmaring *ring;
        int err;
@@ -796,6 +829,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
        ring = kzalloc(sizeof(*ring), GFP_KERNEL);
        if (!ring)
                goto out;
+       ring->type = type;
 
        nr_slots = B43_RXRING_SLOTS;
        if (for_tx)
@@ -818,7 +852,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                                          b43_txhdr_size(dev),
                                          DMA_TO_DEVICE);
 
-               if (dma_mapping_error(dma_test)) {
+               if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) {
                        /* ugh realloc */
                        kfree(ring->txhdr_cache);
                        ring->txhdr_cache = kcalloc(nr_slots,
@@ -832,7 +866,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                                                  b43_txhdr_size(dev),
                                                  DMA_TO_DEVICE);
 
-                       if (dma_mapping_error(dma_test))
+                       if (b43_dma_mapping_error(ring, dma_test,
+                                                 b43_txhdr_size(dev)))
                                goto err_kfree_txhdr_cache;
                }
 
@@ -843,10 +878,9 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 
        ring->dev = dev;
        ring->nr_slots = nr_slots;
-       ring->mmio_base = b43_dmacontroller_base(dma64, controller_index);
+       ring->mmio_base = b43_dmacontroller_base(type, controller_index);
        ring->index = controller_index;
-       ring->dma64 = !!dma64;
-       if (dma64)
+       if (type == B43_DMA_64BIT)
                ring->ops = &dma64_ops;
        else
                ring->ops = &dma32_ops;
@@ -896,8 +930,8 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
        if (!ring)
                return;
 
-       b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
-              (ring->dma64) ? "64" : "32",
+       b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n",
+              (unsigned int)(ring->type),
               ring->mmio_base,
               (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
        /* Device IRQs are disabled prior entering this function,
@@ -941,12 +975,22 @@ int b43_dma_init(struct b43_wldev *dev)
        struct b43_dmaring *ring;
        int err;
        u64 dmamask;
-       int dma64 = 0;
+       enum b43_dmatype type;
 
        dmamask = supported_dma_mask(dev);
-       if (dmamask == DMA_64BIT_MASK)
-               dma64 = 1;
-
+       switch (dmamask) {
+       default:
+               B43_WARN_ON(1);
+       case DMA_30BIT_MASK:
+               type = B43_DMA_30BIT;
+               break;
+       case DMA_32BIT_MASK:
+               type = B43_DMA_32BIT;
+               break;
+       case DMA_64BIT_MASK:
+               type = B43_DMA_64BIT;
+               break;
+       }
        err = ssb_dma_set_mask(dev->dev, dmamask);
        if (err) {
                b43err(dev->wl, "The machine/kernel does not support "
@@ -958,52 +1002,51 @@ int b43_dma_init(struct b43_wldev *dev)
 
        err = -ENOMEM;
        /* setup TX DMA channels. */
-       ring = b43_setup_dmaring(dev, 0, 1, dma64);
+       ring = b43_setup_dmaring(dev, 0, 1, type);
        if (!ring)
                goto out;
        dma->tx_ring0 = ring;
 
-       ring = b43_setup_dmaring(dev, 1, 1, dma64);
+       ring = b43_setup_dmaring(dev, 1, 1, type);
        if (!ring)
                goto err_destroy_tx0;
        dma->tx_ring1 = ring;
 
-       ring = b43_setup_dmaring(dev, 2, 1, dma64);
+       ring = b43_setup_dmaring(dev, 2, 1, type);
        if (!ring)
                goto err_destroy_tx1;
        dma->tx_ring2 = ring;
 
-       ring = b43_setup_dmaring(dev, 3, 1, dma64);
+       ring = b43_setup_dmaring(dev, 3, 1, type);
        if (!ring)
                goto err_destroy_tx2;
        dma->tx_ring3 = ring;
 
-       ring = b43_setup_dmaring(dev, 4, 1, dma64);
+       ring = b43_setup_dmaring(dev, 4, 1, type);
        if (!ring)
                goto err_destroy_tx3;
        dma->tx_ring4 = ring;
 
-       ring = b43_setup_dmaring(dev, 5, 1, dma64);
+       ring = b43_setup_dmaring(dev, 5, 1, type);
        if (!ring)
                goto err_destroy_tx4;
        dma->tx_ring5 = ring;
 
        /* setup RX DMA channels. */
-       ring = b43_setup_dmaring(dev, 0, 0, dma64);
+       ring = b43_setup_dmaring(dev, 0, 0, type);
        if (!ring)
                goto err_destroy_tx5;
        dma->rx_ring0 = ring;
 
        if (dev->dev->id.revision < 5) {
-               ring = b43_setup_dmaring(dev, 3, 0, dma64);
+               ring = b43_setup_dmaring(dev, 3, 0, type);
                if (!ring)
                        goto err_destroy_rx0;
                dma->rx_ring3 = ring;
        }
 
-       b43dbg(dev->wl, "%d-bit DMA initialized\n",
-              (dmamask == DMA_64BIT_MASK) ? 64 :
-              (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+       b43dbg(dev->wl, "%u-bit DMA initialized\n",
+              (unsigned int)type);
        err = 0;
       out:
        return err;
@@ -1146,7 +1189,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
        meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
                                           hdrsize, 1);
-       if (dma_mapping_error(meta_hdr->dmaaddr)) {
+       if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) {
                ring->current_slot = old_top_slot;
                ring->used_slots = old_used_slots;
                return -EIO;
@@ -1165,7 +1208,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
        meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
        /* create a bounce buffer in zone_dma on mapping failure. */
-       if (dma_mapping_error(meta->dmaaddr)) {
+       if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
                bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb) {
                        ring->current_slot = old_top_slot;
@@ -1179,7 +1222,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
                skb = bounce_skb;
                meta->skb = skb;
                meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
-               if (dma_mapping_error(meta->dmaaddr)) {
+               if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
                        ring->current_slot = old_top_slot;
                        ring->used_slots = old_used_slots;
                        err = -EIO;
index 58db03ac536e596e060e94815a0fb0bfbe87d0c0..c0d6b69e650128fa68dc7825f8cf00c10e23f073 100644 (file)
@@ -203,6 +203,12 @@ struct b43_dma_ops {
        void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
 };
 
+enum b43_dmatype {
+       B43_DMA_30BIT   = 30,
+       B43_DMA_32BIT   = 32,
+       B43_DMA_64BIT   = 64,
+};
+
 struct b43_dmaring {
        /* Lowlevel DMA ops. */
        const struct b43_dma_ops *ops;
@@ -235,8 +241,8 @@ struct b43_dmaring {
        int index;
        /* Boolean. Is this a TX ring? */
        bool tx;
-       /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
-       bool dma64;
+       /* The type of DMA engine used. */
+       enum b43_dmatype type;
        /* Boolean. Is this ring stopped at ieee80211 level? */
        bool stopped;
        /* Lock, only used for TX. */
@@ -255,8 +261,7 @@ static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
        return b43_read32(ring->dev, ring->mmio_base + offset);
 }
 
-static inline
-    void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
+static inline void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
 {
        b43_write32(ring->dev, ring->mmio_base + offset, value);
 }
@@ -264,13 +269,6 @@ static inline
 int b43_dma_init(struct b43_wldev *dev);
 void b43_dma_free(struct b43_wldev *dev);
 
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
-                              u16 dmacontroller_mmio_base, int dma64);
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
-                              u16 dmacontroller_mmio_base, int dma64);
-
-u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
-
 void b43_dma_tx_suspend(struct b43_wldev *dev);
 void b43_dma_tx_resume(struct b43_wldev *dev);
 
index 83161d9af813a06a73a7733ea1180217be531094..6e08405e8026cfca7e1a0f74f0418315b89c2bed 100644 (file)
@@ -1164,7 +1164,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 {
        const struct b43legacy_dma_ops *ops = ring->ops;
        u8 *header;
-       int slot;
+       int slot, old_top_slot, old_used_slots;
        int err;
        struct b43legacy_dmadesc_generic *desc;
        struct b43legacy_dmadesc_meta *meta;
@@ -1174,6 +1174,9 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 #define SLOTS_PER_PACKET  2
        B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
 
+       old_top_slot = ring->current_slot;
+       old_used_slots = ring->used_slots;
+
        /* Get a slot for the header. */
        slot = request_slot(ring);
        desc = ops->idx2desc(ring, slot, &meta_hdr);
@@ -1181,9 +1184,14 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 
        header = &(ring->txhdr_cache[slot * sizeof(
                               struct b43legacy_txhdr_fw3)]);
-       b43legacy_generate_txhdr(ring->dev, header,
+       err = b43legacy_generate_txhdr(ring->dev, header,
                                 skb->data, skb->len, ctl,
                                 generate_cookie(ring, slot));
+       if (unlikely(err)) {
+               ring->current_slot = old_top_slot;
+               ring->used_slots = old_used_slots;
+               return err;
+       }
 
        meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
                                       sizeof(struct b43legacy_txhdr_fw3), 1);
@@ -1206,6 +1214,8 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
        if (dma_mapping_error(meta->dmaaddr)) {
                bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb) {
+                       ring->current_slot = old_top_slot;
+                       ring->used_slots = old_used_slots;
                        err = -ENOMEM;
                        goto out_unmap_hdr;
                }
@@ -1216,6 +1226,8 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
                meta->skb = skb;
                meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
                if (dma_mapping_error(meta->dmaaddr)) {
+                       ring->current_slot = old_top_slot;
+                       ring->used_slots = old_used_slots;
                        err = -EIO;
                        goto out_free_bounce;
                }
@@ -1282,6 +1294,13 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
        B43legacy_BUG_ON(ring->stopped);
 
        err = dma_tx_fragment(ring, skb, ctl);
+       if (unlikely(err == -ENOKEY)) {
+               /* Drop this packet, as we don't have the encryption key
+                * anymore and must not transmit it unencrypted. */
+               dev_kfree_skb_any(skb);
+               err = 0;
+               goto out_unlock;
+       }
        if (unlikely(err)) {
                b43legacyerr(dev->wl, "DMA tx mapping failure\n");
                goto out_unlock;
index aa20d5d56e2f479d625c2411c53228ebaa3876e9..53f7f2e97615d0c80b6c918474b9a9ed2684f333 100644 (file)
@@ -3160,8 +3160,6 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
        b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
 
        ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
-       memset(wl->bssid, 0, ETH_ALEN);
-       memset(wl->mac_addr, 0, ETH_ALEN);
        b43legacy_upload_card_macaddress(dev);
        b43legacy_security_init(dev);
        b43legacy_rng_init(wl);
@@ -3263,6 +3261,13 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
         * LEDs that are registered later depend on it. */
        b43legacy_rfkill_init(dev);
 
+       /* Kill all old instance specific information to make sure
+        * the card won't use it in the short timeframe between start
+        * and mac80211 reconfiguring it. */
+       memset(wl->bssid, 0, ETH_ALEN);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       wl->filter_flags = 0;
+
        mutex_lock(&wl->mutex);
 
        if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
index e4f4c5c39e334ebf4c37c0e903b66ec989f71b82..bcdd54eb2edb52683804712201f8ee78260c853b 100644 (file)
@@ -181,7 +181,7 @@ union txhdr_union {
        struct b43legacy_txhdr_fw3 txhdr_fw3;
 };
 
-static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
+static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
                                  struct sk_buff *skb,
                                  struct b43legacy_pio_txpacket *packet,
                                  size_t txhdr_size)
@@ -189,14 +189,17 @@ static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
        union txhdr_union txhdr_data;
        u8 *txhdr = NULL;
        unsigned int octets;
+       int err;
 
        txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
 
        B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
-       b43legacy_generate_txhdr(queue->dev,
+       err = b43legacy_generate_txhdr(queue->dev,
                                 txhdr, skb->data, skb->len,
                                 &packet->txstat.control,
                                 generate_cookie(queue, packet));
+       if (err)
+               return err;
 
        tx_start(queue);
        octets = skb->len + txhdr_size;
@@ -204,6 +207,8 @@ static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
                octets--;
        tx_data(queue, txhdr, (u8 *)skb->data, octets);
        tx_complete(queue, skb);
+
+       return 0;
 }
 
 static void free_txpacket(struct b43legacy_pio_txpacket *packet,
@@ -226,6 +231,7 @@ static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
        struct b43legacy_pioqueue *queue = packet->queue;
        struct sk_buff *skb = packet->skb;
        u16 octets;
+       int err;
 
        octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
        if (queue->tx_devq_size < octets) {
@@ -247,8 +253,14 @@ static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
        if (queue->tx_devq_used + octets > queue->tx_devq_size)
                return -EBUSY;
        /* Now poke the device. */
-       pio_tx_write_fragment(queue, skb, packet,
+       err = pio_tx_write_fragment(queue, skb, packet,
                              sizeof(struct b43legacy_txhdr_fw3));
+       if (unlikely(err == -ENOKEY)) {
+               /* Drop this packet, as we don't have the encryption key
+                * anymore and must not transmit it unencrypted. */
+               free_txpacket(packet, 1);
+               return 0;
+       }
 
        /* Account for the packet size.
         * (We must not overflow the device TX queue)
@@ -486,6 +498,9 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
        queue = parse_cookie(dev, status->cookie, &packet);
        B43legacy_WARN_ON(!queue);
 
+       if (!packet->skb)
+               return;
+
        queue->tx_devq_packets--;
        queue->tx_devq_used -= (packet->skb->len +
                                sizeof(struct b43legacy_txhdr_fw3));
index e20c552442d53892bef644b8d4485dcc66972851..d84408a82db9ef6aa50857a3ad2fa4b4e4da2439 100644 (file)
@@ -181,7 +181,7 @@ static u8 b43legacy_calc_fallback_rate(u8 bitrate)
        return 0;
 }
 
-static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
+static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                               struct b43legacy_txhdr_fw3 *txhdr,
                               const unsigned char *fragment_data,
                               unsigned int fragment_len,
@@ -252,6 +252,13 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
                        iv_len = min((size_t)txctl->iv_len,
                                     ARRAY_SIZE(txhdr->iv));
                        memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
+               } else {
+                       /* This key is invalid. This might only happen
+                        * in a short timeframe after machine resume before
+                        * we were able to reconfigure keys.
+                        * Drop this packet completely. Do not transmit it
+                        * unencrypted to avoid leaking information. */
+                       return -ENOKEY;
                }
        }
        b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
@@ -345,16 +352,18 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
        /* Apply the bitfields */
        txhdr->mac_ctl = cpu_to_le32(mac_ctl);
        txhdr->phy_ctl = cpu_to_le16(phy_ctl);
+
+       return 0;
 }
 
-void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
                              u8 *txhdr,
                              const unsigned char *fragment_data,
                              unsigned int fragment_len,
                              const struct ieee80211_tx_control *txctl,
                              u16 cookie)
 {
-       generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
+       return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
                           fragment_data, fragment_len,
                           txctl, cookie);
 }
index 8a155d0a5d1fbb2c4b7d4528ce7ae900d8a261be..bab47928a0c9b776e5febd7b546e6da3d635827a 100644 (file)
@@ -76,7 +76,7 @@ struct b43legacy_txhdr_fw3 {
 
 
 
-void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
                              u8 *txhdr,
                              const unsigned char *fragment_data,
                              unsigned int fragment_len,
index f55c75712b555bfc179628964cff723cd6fa85ff..5ee1ad69898b6f36aed5b84a2270b9431274e1ab 100644 (file)
@@ -4207,13 +4207,13 @@ static u8 ratio2dB[100] = {
  * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
 int iwl3945_calc_db_from_ratio(int sig_ratio)
 {
-       /* Anything above 1000:1 just report as 60 dB */
-       if (sig_ratio > 1000)
+       /* 1000:1 or higher just report as 60 dB */
+       if (sig_ratio >= 1000)
                return 60;
 
-       /* Above 100:1, divide by 10 and use table,
+       /* 100:1 or higher, divide by 10 and use table,
         *   add 20 dB to make up for divide by 10 */
-       if (sig_ratio > 100)
+       if (sig_ratio >= 100)
                return (20 + (int)ratio2dB[sig_ratio/10]);
 
        /* We shouldn't see this */
index e9743d3efaf682a8a5db6b07d6f841cf7dc2c05d..238628d3a854aa6e45deeaedd3e5dc6372ee1594 100644 (file)
@@ -1540,6 +1540,38 @@ static void __devinit detect_and_report_smsc (void)
        smsc_check(0x3f0,0x44);
        smsc_check(0x370,0x44);
 }
+
+static void __devinit detect_and_report_it87(void)
+{
+       u16 dev;
+       u8 r;
+       if (verbose_probing)
+               printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
+       if (!request_region(0x2e, 1, __FUNCTION__))
+               return;
+       outb(0x87, 0x2e);
+       outb(0x01, 0x2e);
+       outb(0x55, 0x2e);
+       outb(0x55, 0x2e);
+       outb(0x20, 0x2e);
+       dev = inb(0x2f) << 8;
+       outb(0x21, 0x2e);
+       dev |= inb(0x2f);
+       if (dev == 0x8712 || dev == 0x8705 || dev == 0x8715 ||
+           dev == 0x8716 || dev == 0x8718 || dev == 0x8726) {
+               printk(KERN_INFO "IT%04X SuperIO detected.\n", dev);
+               outb(0x07, 0x2E);       /* Parallel Port */
+               outb(0x03, 0x2F);
+               outb(0xF0, 0x2E);       /* BOOT 0x80 off */
+               r = inb(0x2f);
+               outb(0xF0, 0x2E);
+               outb(r | 8, 0x2F);
+               outb(0x02, 0x2E);       /* Lock */
+               outb(0x02, 0x2F);
+
+               release_region(0x2e, 1);
+       }
+}
 #endif /* CONFIG_PARPORT_PC_SUPERIO */
 
 static int get_superio_dma (struct parport *p)
@@ -2767,6 +2799,7 @@ enum parport_pc_pci_cards {
        netmos_9755,
        netmos_9805,
        netmos_9815,
+       quatech_sppxp100,
 };
 
 
@@ -2843,6 +2876,7 @@ static struct parport_pc_pci {
         /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
        /* netmos_9805 */               { 1, { { 0, -1 }, } }, /* untested */
        /* netmos_9815 */               { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */
+       /* quatech_sppxp100 */          { 1, { { 0, 1 }, } },
 };
 
 static const struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2926,6 +2960,9 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
+       /* Quatech SPPXP-100 Parallel port PCI ExpressCard */
+       { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
        { 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
@@ -3159,24 +3196,25 @@ static void __init parport_pc_find_ports (int autoirq, int autodma)
        int count = 0, err;
 
 #ifdef CONFIG_PARPORT_PC_SUPERIO
-       detect_and_report_winbond ();
-       detect_and_report_smsc ();
+       detect_and_report_it87();
+       detect_and_report_winbond();
+       detect_and_report_smsc();
 #endif
 
        /* Onboard SuperIO chipsets that show themselves on the PCI bus. */
-       count += parport_pc_init_superio (autoirq, autodma);
+       count += parport_pc_init_superio(autoirq, autodma);
 
        /* PnP ports, skip detection if SuperIO already found them */
        if (!count) {
-               err = pnp_register_driver (&parport_pc_pnp_driver);
+               err = pnp_register_driver(&parport_pc_pnp_driver);
                if (!err)
                        pnp_registered_parport = 1;
        }
 
        /* ISA ports and whatever (see asm/parport.h). */
-       parport_pc_find_nonpci_ports (autoirq, autodma);
+       parport_pc_find_nonpci_ports(autoirq, autodma);
 
-       err = pci_register_driver (&parport_pc_pci_driver);
+       err = pci_register_driver(&parport_pc_pci_driver);
        if (!err)
                pci_registered_parport = 1;
 }
index bd6ad8b38168a43b3def14876deb7095b6117da9..e2e95b36a603e227be8d0d6b03b30996c9f00c6f 100644 (file)
@@ -77,7 +77,7 @@ static struct parport_pc_pci cards[] __devinitdata = {
        /* titan_110l */                { 1, { { 3, -1 }, } },
        /* titan_210l */                { 1, { { 3, -1 }, } },
        /* netmos_9xx5_combo */         { 1, { { 2, -1 }, }, netmos_parallel_init },
-       /* netmos_9855 */               { 1, { { 0, -1 }, }, netmos_parallel_init },
+       /* netmos_9855 */               { 1, { { 2, -1 }, }, netmos_parallel_init },
        /* avlab_1s1p     */            { 1, { { 1, 2}, } },
        /* avlab_1s2p     */            { 2, { { 1, 2}, { 3, 4 },} },
        /* avlab_2s1p     */            { 1, { { 2, 3}, } },
@@ -185,7 +185,7 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
                .uart_offset    = 8,
        },
        [netmos_9855] = {
-               .flags          = FL_BASE2 | FL_BASE_BARS,
+               .flags          = FL_BASE4 | FL_BASE_BARS,
                .num_ports      = 1,
                .base_baud      = 115200,
                .uart_offset    = 8,
index 91b2dc956be5de68e1ebefe1585e6e79cea62fab..8ed26480371fcf2dc877a0e9d1bc8d3f24fcab11 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pci.h>
 #include <linux/dmar.h>
 #include "iova.h"
+#include "intel-iommu.h"
 
 #undef PREFIX
 #define PREFIX "DMAR:"
index 4e01df99681ac79c1bbd0842d57ead2933af11d3..31fa6c92aa5ef04142dc30b5dc9277a35f46f150 100644 (file)
@@ -1088,7 +1088,7 @@ static void dmar_init_reserved_ranges(void)
        int i;
        u64 addr, size;
 
-       init_iova_domain(&reserved_iova_list);
+       init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
 
        /* IOAPIC ranges shouldn't be accessed by DMA */
        iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
@@ -1142,7 +1142,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
        int adjust_width, agaw;
        unsigned long sagaw;
 
-       init_iova_domain(&domain->iovad);
+       init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
        spin_lock_init(&domain->mapping_lock);
 
        domain_reserve_special_ranges(domain);
index 459ad1f9dc549f5d84635c93429a1dafdd44a978..0e4862675ad23450787577713e31331c078fa826 100644 (file)
 
 #include <linux/types.h>
 #include <linux/msi.h>
+#include <linux/sysdev.h>
 #include "iova.h"
 #include <linux/io.h>
 
+/*
+ * We need a fixed PAGE_SIZE of 4K irrespective of
+ * arch PAGE_SIZE for IOMMU page tables.
+ */
+#define PAGE_SHIFT_4K          (12)
+#define PAGE_SIZE_4K           (1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K           (((u64)-1) << PAGE_SHIFT_4K)
+#define PAGE_ALIGN_4K(addr)    (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
+
+#define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT_4K)
+#define DMA_32BIT_PFN          IOVA_PFN(DMA_32BIT_MASK)
+#define DMA_64BIT_PFN          IOVA_PFN(DMA_64BIT_MASK)
+
 /*
  * Intel IOMMU register specification per version 1.0 public spec.
  */
index a84571c293609bdd3c2d743e73676cde24ce1151..8de7ab6c6d0c11f4772bc1622a303e3c224e1109 100644 (file)
@@ -9,19 +9,19 @@
 #include "iova.h"
 
 void
-init_iova_domain(struct iova_domain *iovad)
+init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit)
 {
        spin_lock_init(&iovad->iova_alloc_lock);
        spin_lock_init(&iovad->iova_rbtree_lock);
        iovad->rbroot = RB_ROOT;
        iovad->cached32_node = NULL;
-
+       iovad->dma_32bit_pfn = pfn_32bit;
 }
 
 static struct rb_node *
 __get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
 {
-       if ((*limit_pfn != DMA_32BIT_PFN) ||
+       if ((*limit_pfn != iovad->dma_32bit_pfn) ||
                (iovad->cached32_node == NULL))
                return rb_last(&iovad->rbroot);
        else {
@@ -37,7 +37,7 @@ static void
 __cached_rbnode_insert_update(struct iova_domain *iovad,
        unsigned long limit_pfn, struct iova *new)
 {
-       if (limit_pfn != DMA_32BIT_PFN)
+       if (limit_pfn != iovad->dma_32bit_pfn)
                return;
        iovad->cached32_node = &new->node;
 }
index ae3028d5a9415e76a076928704c67755e3fe06ec..d521b5b7319c42ebdbade15a45fb41486309611d 100644 (file)
 #include <linux/rbtree.h>
 #include <linux/dma-mapping.h>
 
-/*
- * We need a fixed PAGE_SIZE of 4K irrespective of
- * arch PAGE_SIZE for IOMMU page tables.
- */
-#define PAGE_SHIFT_4K          (12)
-#define PAGE_SIZE_4K           (1UL << PAGE_SHIFT_4K)
-#define PAGE_MASK_4K           (((u64)-1) << PAGE_SHIFT_4K)
-#define PAGE_ALIGN_4K(addr)    (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
-
 /* IO virtual address start page frame number */
 #define IOVA_START_PFN         (1)
 
-#define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT_4K)
-#define DMA_32BIT_PFN  IOVA_PFN(DMA_32BIT_MASK)
-#define DMA_64BIT_PFN  IOVA_PFN(DMA_64BIT_MASK)
-
 /* iova structure */
 struct iova {
        struct rb_node  node;
@@ -44,6 +31,7 @@ struct iova_domain {
        spinlock_t      iova_rbtree_lock; /* Lock to protect update of rbtree */
        struct rb_root  rbroot;         /* iova domain rbtree root */
        struct rb_node  *cached32_node; /* Save last alloced node */
+       unsigned long   dma_32bit_pfn;
 };
 
 struct iova *alloc_iova_mem(void);
@@ -56,7 +44,7 @@ struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size,
 struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
        unsigned long pfn_hi);
 void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
-void init_iova_domain(struct iova_domain *iovad);
+void init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit);
 struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
 void put_iova_domain(struct iova_domain *iovad);
 
index a262762c5b8836e0dc5091317e43359b67443fc9..12a1645a2e4352b3a3cc8e07941a9888dd5567cb 100644 (file)
@@ -161,8 +161,7 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state)
                        return error;
        }
 
-       if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE) &&
-           pnp_can_disable(pnp_dev)) {
+       if (pnp_can_disable(pnp_dev)) {
                error = pnp_stop_dev(pnp_dev);
                if (error)
                        return error;
@@ -185,14 +184,17 @@ static int pnp_bus_resume(struct device *dev)
        if (pnp_dev->protocol && pnp_dev->protocol->resume)
                pnp_dev->protocol->resume(pnp_dev);
 
-       if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
+       if (pnp_can_write(pnp_dev)) {
                error = pnp_start_dev(pnp_dev);
                if (error)
                        return error;
        }
 
-       if (pnp_drv->resume)
-               return pnp_drv->resume(pnp_dev);
+       if (pnp_drv->resume) {
+               error = pnp_drv->resume(pnp_dev);
+               if (error)
+                       return error;
+       }
 
        return 0;
 }
index 31548044fdde9a7ef63d1b154c882b83b034397f..982658477a58b4695df2ac979b00090cba9b1101 100644 (file)
 #include <linux/errno.h>
 #include <linux/list.h>
 #include <linux/types.h>
+#include <linux/pnp.h>
 #include <linux/stat.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 #include "base.h"
@@ -315,8 +318,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev,
        return ret;
 }
 
-extern struct semaphore pnp_res_mutex;
-
 static ssize_t
 pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
                          const char *ubuf, size_t count)
@@ -361,10 +362,10 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
                goto done;
        }
        if (!strnicmp(buf, "get", 3)) {
-               down(&pnp_res_mutex);
+               mutex_lock(&pnp_res_mutex);
                if (pnp_can_read(dev))
                        dev->protocol->get(dev, &dev->res);
-               up(&pnp_res_mutex);
+               mutex_unlock(&pnp_res_mutex);
                goto done;
        }
        if (!strnicmp(buf, "set", 3)) {
@@ -373,7 +374,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
                        goto done;
                buf += 3;
                pnp_init_resource_table(&dev->res);
-               down(&pnp_res_mutex);
+               mutex_lock(&pnp_res_mutex);
                while (1) {
                        while (isspace(*buf))
                                ++buf;
@@ -455,7 +456,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
                        }
                        break;
                }
-               up(&pnp_res_mutex);
+               mutex_unlock(&pnp_res_mutex);
                goto done;
        }
 
index c6b3d4e63ccc62a9ae6e4df684c016eb598fe184..c28caf272c1167f13c761da916af4a0983d878da 100644 (file)
 #include <linux/pnp.h>
 #include <linux/slab.h>
 #include <linux/bitmap.h>
+#include <linux/mutex.h>
 #include "base.h"
 
-DECLARE_MUTEX(pnp_res_mutex);
+DEFINE_MUTEX(pnp_res_mutex);
 
 static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
 {
@@ -297,7 +298,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
        if (!pnp_can_configure(dev))
                return -ENODEV;
 
-       down(&pnp_res_mutex);
+       mutex_lock(&pnp_res_mutex);
        pnp_clean_resource_table(&dev->res);    /* start with a fresh slate */
        if (dev->independent) {
                port = dev->independent->port;
@@ -366,12 +367,12 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
        } else if (dev->dependent)
                goto fail;
 
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
        return 1;
 
 fail:
        pnp_clean_resource_table(&dev->res);
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
        return 0;
 }
 
@@ -396,7 +397,7 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
                return -ENOMEM;
        *bak = dev->res;
 
-       down(&pnp_res_mutex);
+       mutex_lock(&pnp_res_mutex);
        dev->res = *res;
        if (!(mode & PNP_CONFIG_FORCE)) {
                for (i = 0; i < PNP_MAX_PORT; i++) {
@@ -416,14 +417,14 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
                                goto fail;
                }
        }
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
 
        kfree(bak);
        return 0;
 
 fail:
        dev->res = *bak;
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
        kfree(bak);
        return -EINVAL;
 }
@@ -513,7 +514,7 @@ int pnp_activate_dev(struct pnp_dev *dev)
        int error;
 
        if (dev->active)
-               return 0;       /* the device is already active */
+               return 0;
 
        /* ensure resources are allocated */
        if (pnp_auto_config_dev(dev))
@@ -524,7 +525,7 @@ int pnp_activate_dev(struct pnp_dev *dev)
                return error;
 
        dev->active = 1;
-       return 1;
+       return 0;
 }
 
 /**
@@ -538,7 +539,7 @@ int pnp_disable_dev(struct pnp_dev *dev)
        int error;
 
        if (!dev->active)
-               return 0;       /* the device is already disabled */
+               return 0;
 
        error = pnp_stop_dev(dev);
        if (error)
@@ -547,11 +548,11 @@ int pnp_disable_dev(struct pnp_dev *dev)
        dev->active = 0;
 
        /* release the resources so that other devices can use them */
-       down(&pnp_res_mutex);
+       mutex_lock(&pnp_res_mutex);
        pnp_clean_resource_table(&dev->res);
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
 
-       return 1;
+       return 0;
 }
 
 /**
index 6b9840cce0f4a8cdf9b1a2a51c48e186e53015f2..6aa231ef642d3e366b13984a56e524851d9251fa 100644 (file)
@@ -391,8 +391,8 @@ acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle,
                                   pnpacpi_allocated_resource, res);
 }
 
-static void pnpacpi_parse_dma_option(struct pnp_option *option,
-                                    struct acpi_resource_dma *p)
+static __init void pnpacpi_parse_dma_option(struct pnp_option *option,
+                                           struct acpi_resource_dma *p)
 {
        int i;
        struct pnp_dma *dma;
@@ -411,8 +411,8 @@ static void pnpacpi_parse_dma_option(struct pnp_option *option,
        pnp_register_dma_resource(option, dma);
 }
 
-static void pnpacpi_parse_irq_option(struct pnp_option *option,
-                                    struct acpi_resource_irq *p)
+static __init void pnpacpi_parse_irq_option(struct pnp_option *option,
+                                           struct acpi_resource_irq *p)
 {
        int i;
        struct pnp_irq *irq;
@@ -431,8 +431,8 @@ static void pnpacpi_parse_irq_option(struct pnp_option *option,
        pnp_register_irq_resource(option, irq);
 }
 
-static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
-                                        struct acpi_resource_extended_irq *p)
+static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
+                                       struct acpi_resource_extended_irq *p)
 {
        int i;
        struct pnp_irq *irq;
@@ -451,8 +451,8 @@ static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
        pnp_register_irq_resource(option, irq);
 }
 
-static void pnpacpi_parse_port_option(struct pnp_option *option,
-                                     struct acpi_resource_io *io)
+static __init void pnpacpi_parse_port_option(struct pnp_option *option,
+                                            struct acpi_resource_io *io)
 {
        struct pnp_port *port;
 
@@ -470,8 +470,8 @@ static void pnpacpi_parse_port_option(struct pnp_option *option,
        pnp_register_port_resource(option, port);
 }
 
-static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
-                                           struct acpi_resource_fixed_io *io)
+static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
+                                       struct acpi_resource_fixed_io *io)
 {
        struct pnp_port *port;
 
@@ -487,8 +487,8 @@ static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
        pnp_register_port_resource(option, port);
 }
 
-static void pnpacpi_parse_mem24_option(struct pnp_option *option,
-                                      struct acpi_resource_memory24 *p)
+static __init void pnpacpi_parse_mem24_option(struct pnp_option *option,
+                                             struct acpi_resource_memory24 *p)
 {
        struct pnp_mem *mem;
 
@@ -508,8 +508,8 @@ static void pnpacpi_parse_mem24_option(struct pnp_option *option,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpacpi_parse_mem32_option(struct pnp_option *option,
-                                      struct acpi_resource_memory32 *p)
+static __init void pnpacpi_parse_mem32_option(struct pnp_option *option,
+                                             struct acpi_resource_memory32 *p)
 {
        struct pnp_mem *mem;
 
@@ -529,8 +529,8 @@ static void pnpacpi_parse_mem32_option(struct pnp_option *option,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
-                                        struct acpi_resource_fixed_memory32 *p)
+static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
+                                       struct acpi_resource_fixed_memory32 *p)
 {
        struct pnp_mem *mem;
 
@@ -549,8 +549,8 @@ static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpacpi_parse_address_option(struct pnp_option *option,
-                                        struct acpi_resource *r)
+static __init void pnpacpi_parse_address_option(struct pnp_option *option,
+                                               struct acpi_resource *r)
 {
        struct acpi_resource_address64 addr, *p = &addr;
        acpi_status status;
@@ -596,8 +596,8 @@ struct acpipnp_parse_option_s {
        struct pnp_dev *dev;
 };
 
-static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
-                                          void *data)
+static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
+                                                 void *data)
 {
        int priority = 0;
        struct acpipnp_parse_option_s *parse_data = data;
@@ -696,8 +696,8 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
        return AE_OK;
 }
 
-acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
-                                              struct pnp_dev * dev)
+acpi_status __init pnpacpi_parse_resource_option_data(acpi_handle handle,
+                                                     struct pnp_dev *dev)
 {
        acpi_status status;
        struct acpipnp_parse_option_s parse_data;
index e33e03f710841998591b0b8c649f3fb2e2db189e..f7e67197a56847c9d937ab0cb2efd595ee3fc306 100644 (file)
@@ -315,7 +315,7 @@ struct pnp_protocol pnpbios_protocol = {
        .disable = pnpbios_disable_resources,
 };
 
-static int insert_device(struct pnp_bios_node *node)
+static int __init insert_device(struct pnp_bios_node *node)
 {
        struct list_head *pos;
        struct pnp_dev *dev;
index 3fabf11b002722f92ae50e8c591a3b13450b554c..caade3531416f6a7392595f7b5fd432fa2a05660 100644 (file)
@@ -262,8 +262,8 @@ len_err:
  * Resource Configuration Options
  */
 
-static void pnpbios_parse_mem_option(unsigned char *p, int size,
-                                    struct pnp_option *option)
+static __init void pnpbios_parse_mem_option(unsigned char *p, int size,
+                                           struct pnp_option *option)
 {
        struct pnp_mem *mem;
 
@@ -278,8 +278,8 @@ static void pnpbios_parse_mem_option(unsigned char *p, int size,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpbios_parse_mem32_option(unsigned char *p, int size,
-                                      struct pnp_option *option)
+static __init void pnpbios_parse_mem32_option(unsigned char *p, int size,
+                                             struct pnp_option *option)
 {
        struct pnp_mem *mem;
 
@@ -294,8 +294,8 @@ static void pnpbios_parse_mem32_option(unsigned char *p, int size,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
-                                            struct pnp_option *option)
+static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
+                                                   struct pnp_option *option)
 {
        struct pnp_mem *mem;
 
@@ -309,7 +309,7 @@ static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpbios_parse_irq_option(unsigned char *p, int size,
+static __init void pnpbios_parse_irq_option(unsigned char *p, int size,
                                     struct pnp_option *option)
 {
        struct pnp_irq *irq;
@@ -327,7 +327,7 @@ static void pnpbios_parse_irq_option(unsigned char *p, int size,
        pnp_register_irq_resource(option, irq);
 }
 
-static void pnpbios_parse_dma_option(unsigned char *p, int size,
+static __init void pnpbios_parse_dma_option(unsigned char *p, int size,
                                     struct pnp_option *option)
 {
        struct pnp_dma *dma;
@@ -340,8 +340,8 @@ static void pnpbios_parse_dma_option(unsigned char *p, int size,
        pnp_register_dma_resource(option, dma);
 }
 
-static void pnpbios_parse_port_option(unsigned char *p, int size,
-                                     struct pnp_option *option)
+static __init void pnpbios_parse_port_option(unsigned char *p, int size,
+                                            struct pnp_option *option)
 {
        struct pnp_port *port;
 
@@ -356,8 +356,8 @@ static void pnpbios_parse_port_option(unsigned char *p, int size,
        pnp_register_port_resource(option, port);
 }
 
-static void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
-                                           struct pnp_option *option)
+static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
+                                                  struct pnp_option *option)
 {
        struct pnp_port *port;
 
@@ -371,9 +371,9 @@ static void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
        pnp_register_port_resource(option, port);
 }
 
-static unsigned char *pnpbios_parse_resource_option_data(unsigned char *p,
-                                                        unsigned char *end,
-                                                        struct pnp_dev *dev)
+static __init unsigned char *
+pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
+                                       struct pnp_dev *dev)
 {
        unsigned int len, tag;
        int priority = 0;
@@ -781,7 +781,8 @@ len_err:
  * Core Parsing Functions
  */
 
-int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node *node)
+int __init pnpbios_parse_data_stream(struct pnp_dev *dev,
+                                       struct pnp_bios_node *node)
 {
        unsigned char *p = (char *)node->data;
        unsigned char *end = (char *)(node->data + node->size);
index e903b8c2b1fa5e200e2140d609deb643ea49d195..4065139753b6c4b6e9e1becf06df11234bde8b5f 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/pnp.h>
 #include <linux/io.h>
+#include <linux/dmi.h>
 #include <linux/kallsyms.h>
 #include "base.h"
 
@@ -108,6 +109,46 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
                       "pnp: SB audio device quirk - increasing port range\n");
 }
 
+static void quirk_supermicro_h8dce_system(struct pnp_dev *dev)
+{
+       int i;
+       static struct dmi_system_id supermicro_h8dce[] = {
+               {
+                       .ident = "Supermicro H8DCE",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "H8DCE"),
+                       },
+               },
+               { }
+       };
+
+       if (!dmi_check_system(supermicro_h8dce))
+               return;
+
+       /*
+        * On the Supermicro H8DCE, there's a system device with resources
+        * that overlap BAR 6 of the built-in SATA PCI adapter.  If the PNP
+        * system device claims them, the sata_nv driver won't be able to.
+        * More details at:
+        *     https://bugzilla.redhat.com/show_bug.cgi?id=280641
+        *     https://bugzilla.redhat.com/show_bug.cgi?id=313491
+        *     http://lkml.org/lkml/2008/1/9/449
+        *     http://thread.gmane.org/gmane.linux.acpi.devel/27312
+        */
+       for (i = 0; i < PNP_MAX_MEM; i++) {
+               if (pnp_mem_valid(dev, i) && pnp_mem_len(dev, i) &&
+                   (pnp_mem_start(dev, i) & 0xdfef0000) == 0xdfef0000) {
+                       dev_warn(&dev->dev, "disabling 0x%llx-0x%llx to prevent"
+                               " conflict with sata_nv PCI device\n",
+                               (unsigned long long) pnp_mem_start(dev, i),
+                               (unsigned long long) (pnp_mem_start(dev, i) +
+                                       pnp_mem_len(dev, i) - 1));
+                       pnp_mem_flags(dev, i) = 0;
+               }
+       }
+}
+
 /*
  *  PnP Quirks
  *  Cards or devices that need some tweaking due to incomplete resource info
@@ -128,6 +169,8 @@ static struct pnp_fixup pnp_fixups[] = {
        {"CTL0043", quirk_sb16audio_resources},
        {"CTL0044", quirk_sb16audio_resources},
        {"CTL0045", quirk_sb16audio_resources},
+       {"PNP0c01", quirk_supermicro_h8dce_system},
+       {"PNP0c02", quirk_supermicro_h8dce_system},
        {""}
 };
 
index d4824840c5bfc9c8bb877399014e01305adf3862..13399d133b94a730648fac1e908b7caef0005733 100644 (file)
@@ -106,7 +106,6 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(energy_now),
        POWER_SUPPLY_ATTR(energy_avg),
        POWER_SUPPLY_ATTR(capacity),
-       POWER_SUPPLY_ATTR(capacity_level),
        POWER_SUPPLY_ATTR(temp),
        POWER_SUPPLY_ATTR(temp_ambient),
        POWER_SUPPLY_ATTR(time_to_empty_now),
index 87b3493d88e5bea0f93b3fc0ef412bbb1232a722..6f2f90ebb020db95256f2bc135414ada5ca77d83 100644 (file)
@@ -78,23 +78,21 @@ static const struct avset_video_mode {
        u32 aspect;
        u32 x;
        u32 y;
-       u32 interlace;
-       u32 freq;
 } video_mode_table[] = {
        {     0, }, /* auto */
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I,       A_N,  720,  480, 1, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P,       A_N,  720,  480, 0, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ,  A_N, 1280,  720, 0, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I,       A_N,  720,  576, 1, 50},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P,       A_N,  720,  576, 0, 50},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ,  A_N, 1280,  720, 0, 50},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50},
-       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA,       A_W, 1280,  768, 0, 60},
-       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA,       A_N, 1280, 1024, 0, 60},
-       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA,      A_W, 1920, 1200, 0, 60},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I,       A_N,  720,  480},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P,       A_N,  720,  480},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ,  A_N, 1280,  720},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I,       A_N,  720,  576},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P,       A_N,  720,  576},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ,  A_N, 1280,  720},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080},
+       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA,       A_W, 1280,  768},
+       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA,       A_N, 1280, 1024},
+       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA,      A_W, 1920, 1200},
 };
 
 /* supported CIDs */
@@ -544,7 +542,7 @@ static void ps3av_set_videomode_packet(u32 id)
 
 static void ps3av_set_videomode_cont(u32 id, u32 old_id)
 {
-       static int vesa = 0;
+       static int vesa;
        int res;
 
        /* video signal off */
@@ -554,9 +552,9 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
         * AV backend needs non-VESA mode setting at least one time
         * when VESA mode is used.
         */
-       if (vesa == 0 && (id & PS3AV_MODE_MASK) >= 11) {
+       if (vesa == 0 && (id & PS3AV_MODE_MASK) >= PS3AV_MODE_WXGA) {
                /* vesa mode */
-               ps3av_set_videomode_packet(2);  /* 480P */
+               ps3av_set_videomode_packet(PS3AV_MODE_480P);
        }
        vesa = 1;
 
@@ -596,20 +594,21 @@ static const struct {
        unsigned mask : 19;
        unsigned id :  4;
 } ps3av_preferred_modes[] = {
-       { .mask = PS3AV_RESBIT_WUXGA            << SHIFT_VESA,  .id = 13 },
-       { .mask = PS3AV_RESBIT_1920x1080P       << SHIFT_60,    .id = 5 },
-       { .mask = PS3AV_RESBIT_1920x1080P       << SHIFT_50,    .id = 10 },
-       { .mask = PS3AV_RESBIT_1920x1080I       << SHIFT_60,    .id = 4 },
-       { .mask = PS3AV_RESBIT_1920x1080I       << SHIFT_50,    .id = 9 },
-       { .mask = PS3AV_RESBIT_SXGA             << SHIFT_VESA,  .id = 12 },
-       { .mask = PS3AV_RESBIT_WXGA             << SHIFT_VESA,  .id = 11 },
-       { .mask = PS3AV_RESBIT_1280x720P        << SHIFT_60,    .id = 3 },
-       { .mask = PS3AV_RESBIT_1280x720P        << SHIFT_50,    .id = 8 },
-       { .mask = PS3AV_RESBIT_720x480P         << SHIFT_60,    .id = 2 },
-       { .mask = PS3AV_RESBIT_720x576P         << SHIFT_50,    .id = 7 },
+       { PS3AV_RESBIT_WUXGA      << SHIFT_VESA, PS3AV_MODE_WUXGA   },
+       { PS3AV_RESBIT_1920x1080P << SHIFT_60,   PS3AV_MODE_1080P60 },
+       { PS3AV_RESBIT_1920x1080P << SHIFT_50,   PS3AV_MODE_1080P50 },
+       { PS3AV_RESBIT_1920x1080I << SHIFT_60,   PS3AV_MODE_1080I60 },
+       { PS3AV_RESBIT_1920x1080I << SHIFT_50,   PS3AV_MODE_1080I50 },
+       { PS3AV_RESBIT_SXGA       << SHIFT_VESA, PS3AV_MODE_SXGA    },
+       { PS3AV_RESBIT_WXGA       << SHIFT_VESA, PS3AV_MODE_WXGA    },
+       { PS3AV_RESBIT_1280x720P  << SHIFT_60,   PS3AV_MODE_720P60  },
+       { PS3AV_RESBIT_1280x720P  << SHIFT_50,   PS3AV_MODE_720P50  },
+       { PS3AV_RESBIT_720x480P   << SHIFT_60,   PS3AV_MODE_480P    },
+       { PS3AV_RESBIT_720x576P   << SHIFT_50,   PS3AV_MODE_576P    },
 };
 
-static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa)
+static enum ps3av_mode_num ps3av_resbit2id(u32 res_50, u32 res_60,
+                                          u32 res_vesa)
 {
        unsigned int i;
        u32 res_all;
@@ -638,9 +637,9 @@ static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa)
        return 0;
 }
 
-static int ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
+static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
 {
-       int id;
+       enum ps3av_mode_num id;
 
        if (safe_mode)
                return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60;
@@ -854,7 +853,7 @@ int ps3av_set_video_mode(u32 id)
 
        /* auto mode */
        option = id & ~PS3AV_MODE_MASK;
-       if ((id & PS3AV_MODE_MASK) == 0) {
+       if ((id & PS3AV_MODE_MASK) == PS3AV_MODE_AUTO) {
                id = ps3av_auto_videomode(&ps3av->av_hw_conf);
                if (id < 1) {
                        printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
@@ -889,36 +888,6 @@ int ps3av_get_mode(void)
 
 EXPORT_SYMBOL_GPL(ps3av_get_mode);
 
-int ps3av_get_scanmode(int id)
-{
-       int size;
-
-       id = id & PS3AV_MODE_MASK;
-       size = ARRAY_SIZE(video_mode_table);
-       if (id > size - 1 || id < 0) {
-               printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
-               return -EINVAL;
-       }
-       return video_mode_table[id].interlace;
-}
-
-EXPORT_SYMBOL_GPL(ps3av_get_scanmode);
-
-int ps3av_get_refresh_rate(int id)
-{
-       int size;
-
-       id = id & PS3AV_MODE_MASK;
-       size = ARRAY_SIZE(video_mode_table);
-       if (id > size - 1 || id < 0) {
-               printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
-               return -EINVAL;
-       }
-       return video_mode_table[id].freq;
-}
-
-EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate);
-
 /* get resolution by video_mode */
 int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
 {
@@ -990,7 +959,7 @@ static int ps3av_probe(struct ps3_system_bus_device *dev)
                return -ENOMEM;
 
        mutex_init(&ps3av->mutex);
-       ps3av->ps3av_mode = 0;
+       ps3av->ps3av_mode = PS3AV_MODE_AUTO;
        ps3av->dev = dev;
 
        INIT_WORK(&ps3av->work, ps3avd);
index 45e4b9648176f07f27ba05ac53d3d8e07639ba22..6402d699072b5a28a11069a5188dd2e34245a079 100644 (file)
@@ -20,6 +20,10 @@ menuconfig RTC_CLASS
 
 if RTC_CLASS
 
+if GEN_RTC || RTC
+comment "Conflicting RTC option has been selected, check GEN_RTC and RTC"
+endif
+
 config RTC_HCTOSYS
        bool "Set system time from RTC on startup and resume"
        depends on RTC_CLASS = y
@@ -49,7 +53,7 @@ config RTC_HCTOSYS_DEVICE
 
          If the clock you specify here is not battery backed, it may still
          be useful to reinitialize system time when resuming from system
-         sleep states.  Do not specify an RTC here unless it stays powered
+         sleep states. Do not specify an RTC here unless it stays powered
          during all this system's supported sleep states.
 
 config RTC_DEBUG
@@ -142,7 +146,7 @@ config RTC_DRV_DS1307
          will be called rtc-ds1307.
 
 config RTC_DRV_DS1374
-       tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
+       tristate "Dallas/Maxim DS1374"
        depends on RTC_CLASS && I2C
        help
          If you say yes here you get support for Dallas Semiconductor
@@ -162,7 +166,7 @@ config RTC_DRV_DS1672
          will be called rtc-ds1672.
 
 config RTC_DRV_MAX6900
-       tristate "Maxim 6900"
+       tristate "Maxim MAX6900"
        help
          If you say yes here you will get support for the
          Maxim MAX6900 I2C RTC chip.
@@ -180,10 +184,10 @@ config RTC_DRV_RS5C372
          will be called rtc-rs5c372.
 
 config RTC_DRV_ISL1208
-       tristate "Intersil 1208"
+       tristate "Intersil ISL1208"
        help
          If you say yes here you get support for the
-         Intersil 1208 RTC chip.
+         Intersil ISL1208 RTC chip.
 
          This driver can also be built as a module. If so, the module
          will be called rtc-isl1208.
@@ -220,7 +224,7 @@ config RTC_DRV_PCF8583
          will be called rtc-pcf8583.
 
 config RTC_DRV_M41T80
-       tristate "ST M41T80 series RTC"
+       tristate "ST M41T80/81/82/83/84/85/87"
        help
          If you say Y here you will get support for the
          ST M41T80 RTC chips series. Currently following chips are
@@ -252,23 +256,32 @@ comment "SPI RTC drivers"
 
 if SPI_MASTER
 
-config RTC_DRV_RS5C348
-       tristate "Ricoh RS5C348A/B"
+config RTC_DRV_MAX6902
+       tristate "Maxim MAX6902"
        help
-         If you say yes here you get support for the
-         Ricoh RS5C348A and RS5C348B RTC chips.
+         If you say yes here you will get support for the
+         Maxim MAX6902 SPI RTC chip.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-rs5c348.
+         will be called rtc-max6902.
 
-config RTC_DRV_MAX6902
-       tristate "Maxim 6902"
+config RTC_DRV_R9701
+       tristate "Epson RTC-9701JE"
        help
          If you say yes here you will get support for the
-         Maxim MAX6902 SPI RTC chip.
+         Epson RTC-9701JE SPI RTC chip.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-max6902.
+         will be called rtc-r9701.
+
+config RTC_DRV_RS5C348
+       tristate "Ricoh RS5C348A/B"
+       help
+         If you say yes here you get support for the
+         Ricoh RS5C348A and RS5C348B RTC chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-rs5c348.
 
 endif # SPI_MASTER
 
@@ -302,34 +315,50 @@ config RTC_DRV_DS1216
        help
          If you say yes here you get support for the Dallas DS1216 RTC chips.
 
-config RTC_DRV_DS1553
-       tristate "Dallas DS1553"
+config RTC_DRV_DS1302
+       tristate "Dallas DS1302"
+       depends on SH_SECUREEDGE5410
+       help
+         If you say yes here you get support for the Dallas DS1302 RTC chips.
+
+config RTC_DRV_DS1511
+       tristate "Dallas DS1511"
+       depends on RTC_CLASS
        help
          If you say yes here you get support for the
-         Dallas DS1553 timekeeping chip.
+         Dallas DS1511 timekeeping/watchdog chip.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-ds1553.
+         will be called rtc-ds1511.
 
-config RTC_DRV_STK17TA8
-       tristate "Simtek STK17TA8"
-       depends on RTC_CLASS
+config RTC_DRV_DS1553
+       tristate "Maxim/Dallas DS1553"
        help
          If you say yes here you get support for the
-         Simtek STK17TA8 timekeeping chip.
+         Maxim/Dallas DS1553 timekeeping chip.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-stk17ta8.
+         will be called rtc-ds1553.
 
 config RTC_DRV_DS1742
-       tristate "Dallas DS1742/1743"
+       tristate "Maxim/Dallas DS1742/1743"
        help
          If you say yes here you get support for the
-         Dallas DS1742/1743 timekeeping chip.
+         Maxim/Dallas DS1742/1743 timekeeping chip.
 
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1742.
 
+config RTC_DRV_STK17TA8
+       tristate "Simtek STK17TA8"
+       depends on RTC_CLASS
+       help
+         If you say yes here you get support for the
+         Simtek STK17TA8 timekeeping chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-stk17ta8.
+
 config RTC_DRV_M48T86
        tristate "ST M48T86/Dallas DS12887"
        help
@@ -440,10 +469,47 @@ config RTC_DRV_AT32AP700X
          AT32AP700x family processors.
 
 config RTC_DRV_AT91RM9200
-       tristate "AT91RM9200"
-       depends on ARCH_AT91RM9200
-       help
-         Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
+       tristate "AT91RM9200 or AT91SAM9RL"
+       depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL
+       help
+         Driver for the internal RTC (Realtime Clock) module found on
+         Atmel AT91RM9200's and AT91SAM9RL chips.  On SAM9RL chips
+         this is powered by the backup power supply.
+
+config RTC_DRV_AT91SAM9
+       tristate "AT91SAM9x"
+       depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
+       help
+         RTC driver for the Atmel AT91SAM9x internal RTT (Real Time Timer).
+         These timers are powered by the backup power supply (such as a
+         small coin cell battery), but do not need to be used as RTCs.
+
+         (On AT91SAM9rl chips you probably want to use the dedicated RTC
+         module and leave the RTT available for other uses.)
+
+config RTC_DRV_AT91SAM9_RTT
+       int
+       range 0 1
+       default 0
+       prompt "RTT module Number" if ARCH_AT91SAM9263
+       depends on RTC_DRV_AT91SAM9
+       help
+         More than one RTT module is available.  You can choose which
+         one will be used as an RTC.  The default of zero is normally
+         OK to use, though some systems use that for non-RTC purposes.
+
+config RTC_DRV_AT91SAM9_GPBR
+       int
+       range 0 3 if !ARCH_AT91SAM9263
+       range 0 15 if ARCH_AT91SAM9263
+       default 0
+       prompt "Backup Register Number"
+       depends on RTC_DRV_AT91SAM9
+       help
+         The RTC driver needs to use one of the General Purpose Backup
+         Registers (GPBRs) as well as the RTT.  You can choose which one
+         will be used.  The default of zero is normally OK to use, but
+         on some systems other software needs to use that register.
 
 config RTC_DRV_BFIN
        tristate "Blackfin On-Chip RTC"
index 465db4dd50b2e97232098c1287bbbcacc31db3cc..ec703f34ab864da930d3eadbe594d0ca67fb5bfa 100644 (file)
@@ -19,11 +19,14 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
+obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
 obj-$(CONFIG_RTC_DRV_BFIN)     += rtc-bfin.o
 obj-$(CONFIG_RTC_DRV_CMOS)     += rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_DS1216)   += rtc-ds1216.o
+obj-$(CONFIG_RTC_DRV_DS1302)   += rtc-ds1302.o
 obj-$(CONFIG_RTC_DRV_DS1307)   += rtc-ds1307.o
 obj-$(CONFIG_RTC_DRV_DS1374)   += rtc-ds1374.o
+obj-$(CONFIG_RTC_DRV_DS1511)   += rtc-ds1511.o
 obj-$(CONFIG_RTC_DRV_DS1553)   += rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_DS1672)   += rtc-ds1672.o
 obj-$(CONFIG_RTC_DRV_DS1742)   += rtc-ds1742.o
@@ -38,6 +41,7 @@ obj-$(CONFIG_RTC_DRV_OMAP)    += rtc-omap.o
 obj-$(CONFIG_RTC_DRV_PCF8563)  += rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)  += rtc-pcf8583.o
 obj-$(CONFIG_RTC_DRV_PL031)    += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RS5C313)  += rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_RS5C348)  += rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_RS5C372)  += rtc-rs5c372.o
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
new file mode 100644 (file)
index 0000000..bbf10ec
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * "RTT as Real Time Clock" driver for AT91SAM9 SoC family
+ *
+ * (C) 2007 Michel Benoit
+ *
+ * Based on rtc-at91rm9200.c by Rick Bronson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+
+#include <asm/mach/time.h>
+#include <asm/arch/board.h>
+#include <asm/arch/at91_rtt.h>
+
+
+/*
+ * This driver uses two configurable hardware resources that live in the
+ * AT91SAM9 backup power domain (intended to be powered at all times)
+ * to implement the Real Time Clock interfaces
+ *
+ *  - A "Real-time Timer" (RTT) counts up in seconds from a base time.
+ *    We can't assign the counter value (CRTV) ... but we can reset it.
+ *
+ *  - One of the "General Purpose Backup Registers" (GPBRs) holds the
+ *    base time, normally an offset from the beginning of the POSIX
+ *    epoch (1970-Jan-1 00:00:00 UTC).  Some systems also include the
+ *    local timezone's offset.
+ *
+ * The RTC's value is the RTT counter plus that offset.  The RTC's alarm
+ * is likewise a base (ALMV) plus that offset.
+ *
+ * Not all RTTs will be used as RTCs; some systems have multiple RTTs to
+ * choose from, or a "real" RTC module.  All systems have multiple GPBR
+ * registers available, likewise usable for more than "RTC" support.
+ */
+
+/*
+ * We store ALARM_DISABLED in ALMV to record that no alarm is set.
+ * It's also the reset value for that field.
+ */
+#define ALARM_DISABLED ((u32)~0)
+
+
+struct sam9_rtc {
+       void __iomem            *rtt;
+       struct rtc_device       *rtcdev;
+       u32                     imr;
+};
+
+#define rtt_readl(rtc, field) \
+       __raw_readl((rtc)->rtt + AT91_RTT_ ## field)
+#define rtt_writel(rtc, field, val) \
+       __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
+
+#define gpbr_readl(rtc) \
+       at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR)
+#define gpbr_writel(rtc, val) \
+       at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val))
+
+/*
+ * Read current time and date in RTC
+ */
+static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       u32 secs, secs2;
+       u32 offset;
+
+       /* read current time offset */
+       offset = gpbr_readl(rtc);
+       if (offset == 0)
+               return -EILSEQ;
+
+       /* reread the counter to help sync the two clock domains */
+       secs = rtt_readl(rtc, VR);
+       secs2 = rtt_readl(rtc, VR);
+       if (secs != secs2)
+               secs = rtt_readl(rtc, VR);
+
+       rtc_time_to_tm(offset + secs, tm);
+
+       dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime",
+               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       return 0;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       int err;
+       u32 offset, alarm, mr;
+       unsigned long secs;
+
+       dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime",
+               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       err = rtc_tm_to_time(tm, &secs);
+       if (err != 0)
+               return err;
+
+       mr = rtt_readl(rtc, MR);
+
+       /* disable interrupts */
+       rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+
+       /* read current time offset */
+       offset = gpbr_readl(rtc);
+
+       /* store the new base time in a battery backup register */
+       secs += 1;
+       gpbr_writel(rtc, secs);
+
+       /* adjust the alarm time for the new base */
+       alarm = rtt_readl(rtc, AR);
+       if (alarm != ALARM_DISABLED) {
+               if (offset > secs) {
+                       /* time jumped backwards, increase time until alarm */
+                       alarm += (offset - secs);
+               } else if ((alarm + offset) > secs) {
+                       /* time jumped forwards, decrease time until alarm */
+                       alarm -= (secs - offset);
+               } else {
+                       /* time jumped past the alarm, disable alarm */
+                       alarm = ALARM_DISABLED;
+                       mr &= ~AT91_RTT_ALMIEN;
+               }
+               rtt_writel(rtc, AR, alarm);
+       }
+
+       /* reset the timer, and re-enable interrupts */
+       rtt_writel(rtc, MR, mr | AT91_RTT_RTTRST);
+
+       return 0;
+}
+
+static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       struct rtc_time *tm = &alrm->time;
+       u32 alarm = rtt_readl(rtc, AR);
+       u32 offset;
+
+       offset = gpbr_readl(rtc);
+       if (offset == 0)
+               return -EILSEQ;
+
+       memset(alrm, 0, sizeof(alrm));
+       if (alarm != ALARM_DISABLED && offset != 0) {
+               rtc_time_to_tm(offset + alarm, tm);
+
+               dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm",
+                       1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+                       tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+               if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN)
+                       alrm->enabled = 1;
+       }
+
+       return 0;
+}
+
+static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       struct rtc_time *tm = &alrm->time;
+       unsigned long secs;
+       u32 offset;
+       u32 mr;
+       int err;
+
+       err = rtc_tm_to_time(tm, &secs);
+       if (err != 0)
+               return err;
+
+       offset = gpbr_readl(rtc);
+       if (offset == 0) {
+               /* time is not set */
+               return -EILSEQ;
+       }
+       mr = rtt_readl(rtc, MR);
+       rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+
+       /* alarm in the past? finish and leave disabled */
+       if (secs <= offset) {
+               rtt_writel(rtc, AR, ALARM_DISABLED);
+               return 0;
+       }
+
+       /* else set alarm and maybe enable it */
+       rtt_writel(rtc, AR, secs - offset);
+       if (alrm->enabled)
+               rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
+
+       dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm",
+               tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
+               tm->tm_min, tm->tm_sec);
+
+       return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
+                       unsigned long arg)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       int ret = 0;
+       u32 mr = rtt_readl(rtc, MR);
+
+       dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr);
+
+       switch (cmd) {
+       case RTC_AIE_OFF:               /* alarm off */
+               rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+               break;
+       case RTC_AIE_ON:                /* alarm on */
+               rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
+               break;
+       case RTC_UIE_OFF:               /* update off */
+               rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
+               break;
+       case RTC_UIE_ON:                /* update on */
+               rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN);
+               break;
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * Provide additional RTC information in /proc/driver/rtc
+ */
+static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       u32 mr = mr = rtt_readl(rtc, MR);
+
+       seq_printf(seq, "update_IRQ\t: %s\n",
+                       (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
+       return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+{
+       struct sam9_rtc *rtc = _rtc;
+       u32 sr, mr;
+       unsigned long events = 0;
+
+       /* Shared interrupt may be for another device.  Note: reading
+        * SR clears it, so we must only read it in this irq handler!
+        */
+       mr = rtt_readl(rtc, MR) & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+       sr = rtt_readl(rtc, SR) & mr;
+       if (!sr)
+               return IRQ_NONE;
+
+       /* alarm status */
+       if (sr & AT91_RTT_ALMS)
+               events |= (RTC_AF | RTC_IRQF);
+
+       /* timer update/increment */
+       if (sr & AT91_RTT_RTTINC)
+               events |= (RTC_UF | RTC_IRQF);
+
+       rtc_update_irq(rtc->rtcdev, 1, events);
+
+       pr_debug("%s: num=%ld, events=0x%02lx\n", __FUNCTION__,
+               events >> 8, events & 0x000000FF);
+
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops at91_rtc_ops = {
+       .ioctl          = at91_rtc_ioctl,
+       .read_time      = at91_rtc_readtime,
+       .set_time       = at91_rtc_settime,
+       .read_alarm     = at91_rtc_readalarm,
+       .set_alarm      = at91_rtc_setalarm,
+       .proc           = at91_rtc_proc,
+};
+
+/*
+ * Initialize and install RTC driver
+ */
+static int __init at91_rtc_probe(struct platform_device *pdev)
+{
+       struct resource *r;
+       struct sam9_rtc *rtc;
+       int             ret;
+       u32             mr;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r)
+               return -ENODEV;
+
+       rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
+       if (!rtc)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, rtc);
+       rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS);
+       rtc->rtt += r->start;
+
+       mr = rtt_readl(rtc, MR);
+
+       /* unless RTT is counting at 1 Hz, re-initialize it */
+       if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) {
+               mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES);
+               gpbr_writel(rtc, 0);
+       }
+
+       /* disable all interrupts (same as on shutdown path) */
+       mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+       rtt_writel(rtc, MR, mr);
+
+       rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
+                               &at91_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtcdev)) {
+               ret = PTR_ERR(rtc->rtcdev);
+               goto fail;
+       }
+
+       /* register irq handler after we know what name we'll use */
+       ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
+                               IRQF_DISABLED | IRQF_SHARED,
+                               rtc->rtcdev->dev.bus_id, rtc);
+       if (ret) {
+               dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
+               rtc_device_unregister(rtc->rtcdev);
+               goto fail;
+       }
+
+       /* NOTE:  sam9260 rev A silicon has a ROM bug which resets the
+        * RTT on at least some reboots.  If you have that chip, you must
+        * initialize the time from some external source like a GPS, wall
+        * clock, discrete RTC, etc
+        */
+
+       if (gpbr_readl(rtc) == 0)
+               dev_warn(&pdev->dev, "%s: SET TIME!\n",
+                               rtc->rtcdev->dev.bus_id);
+
+       return 0;
+
+fail:
+       platform_set_drvdata(pdev, NULL);
+       kfree(rtc);
+       return ret;
+}
+
+/*
+ * Disable and remove the RTC driver
+ */
+static int __exit at91_rtc_remove(struct platform_device *pdev)
+{
+       struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+       u32             mr = rtt_readl(rtc, MR);
+
+       /* disable all interrupts */
+       rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+       free_irq(AT91_ID_SYS, rtc);
+
+       rtc_device_unregister(rtc->rtcdev);
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(rtc);
+       return 0;
+}
+
+static void at91_rtc_shutdown(struct platform_device *pdev)
+{
+       struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+       u32             mr = rtt_readl(rtc, MR);
+
+       rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+       rtt_writel(rtc, MR, mr & ~rtc->imr);
+}
+
+#ifdef CONFIG_PM
+
+/* AT91SAM9 RTC Power management control */
+
+static int at91_rtc_suspend(struct platform_device *pdev,
+                                       pm_message_t state)
+{
+       struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+       u32             mr = rtt_readl(rtc, MR);
+
+       /*
+        * This IRQ is shared with DBGU and other hardware which isn't
+        * necessarily a wakeup event source.
+        */
+       rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+       if (rtc->imr) {
+               if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) {
+                       enable_irq_wake(AT91_ID_SYS);
+                       /* don't let RTTINC cause wakeups */
+                       if (mr & AT91_RTT_RTTINCIEN)
+                               rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
+               } else
+                       rtt_writel(rtc, MR, mr & ~rtc->imr);
+       }
+
+       return 0;
+}
+
+static int at91_rtc_resume(struct platform_device *pdev)
+{
+       struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+       u32             mr;
+
+       if (rtc->imr) {
+               if (device_may_wakeup(&pdev->dev))
+                       disable_irq_wake(AT91_ID_SYS);
+               mr = rtt_readl(rtc, MR);
+               rtt_writel(rtc, MR, mr | rtc->imr);
+       }
+
+       return 0;
+}
+#else
+#define at91_rtc_suspend       NULL
+#define at91_rtc_resume                NULL
+#endif
+
+static struct platform_driver at91_rtc_driver = {
+       .driver.name    = "rtc-at91sam9",
+       .driver.owner   = THIS_MODULE,
+       .remove         = __exit_p(at91_rtc_remove),
+       .shutdown       = at91_rtc_shutdown,
+       .suspend        = at91_rtc_suspend,
+       .resume         = at91_rtc_resume,
+};
+
+/* Chips can have more than one RTT module, and they can be used for more
+ * than just RTCs.  So we can't just register as "the" RTT driver.
+ *
+ * A normal approach in such cases is to create a library to allocate and
+ * free the modules.  Here we just use bus_find_device() as like such a
+ * library, binding directly ... no runtime "library" footprint is needed.
+ */
+static int __init at91_rtc_match(struct device *dev, void *v)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       int ret;
+
+       /* continue searching if this isn't the RTT we need */
+       if (strcmp("at91_rtt", pdev->name) != 0
+                       || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT)
+               goto fail;
+
+       /* else we found it ... but fail unless we can bind to the RTC driver */
+       if (dev->driver) {
+               dev_dbg(dev, "busy, can't use as RTC!\n");
+               goto fail;
+       }
+       dev->driver = &at91_rtc_driver.driver;
+       if (device_attach(dev) == 0) {
+               dev_dbg(dev, "can't attach RTC!\n");
+               goto fail;
+       }
+       ret = at91_rtc_probe(pdev);
+       if (ret == 0)
+               return true;
+
+       dev_dbg(dev, "RTC probe err %d!\n", ret);
+fail:
+       return false;
+}
+
+static int __init at91_rtc_init(void)
+{
+       int status;
+       struct device *rtc;
+
+       status = platform_driver_register(&at91_rtc_driver);
+       if (status)
+               return status;
+       rtc = bus_find_device(&platform_bus_type, NULL,
+                       NULL, at91_rtc_match);
+       if (!rtc)
+               platform_driver_unregister(&at91_rtc_driver);
+       return rtc ? 0 : -ENODEV;
+}
+module_init(at91_rtc_init);
+
+static void __exit at91_rtc_exit(void)
+{
+       platform_driver_unregister(&at91_rtc_driver);
+}
+module_exit(at91_rtc_exit);
+
+
+MODULE_AUTHOR("Michel Benoit");
+MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x");
+MODULE_LICENSE("GPL");
index 1aa709dda0d67d0fbb9e5d660211e207b22ca3ba..d90ba860d21678863610a69a3dc9a74f5b9e53bd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Blackfin On-Chip Real Time Clock Driver
- *  Supports BF53[123]/BF53[467]/BF54[2489]
+ *  Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789]
  *
  * Copyright 2004-2007 Analog Devices Inc.
  *
  * writes to clear status registers complete immediately.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/bcd.h>
-#include <linux/rtc.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/rtc.h>
 #include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
 
 #include <asm/blackfin.h>
 
-#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __FUNCTION__, __LINE__, ## args)
-#define stampit() stamp("here i am")
+#define dev_dbg_stamp(dev) dev_dbg(dev, "%s:%i: here i am\n", __func__, __LINE__)
 
 struct bfin_rtc {
        struct rtc_device *rtc_dev;
        struct rtc_time rtc_alarm;
-       spinlock_t lock;
+       u16 rtc_wrote_regs;
 };
 
 /* Bit values for the ISTAT / ICTL registers */
@@ -72,7 +71,7 @@ struct bfin_rtc {
 #define SEC_BITS_OFF    0
 
 /* Some helper functions to convert between the common RTC notion of time
- * and the internal Blackfin notion that is stored in 32bits.
+ * and the internal Blackfin notion that is encoded in 32bits.
  */
 static inline u32 rtc_time_to_bfin(unsigned long now)
 {
@@ -97,7 +96,10 @@ static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm)
        rtc_time_to_tm(rtc_bfin_to_time(rtc_bfin), tm);
 }
 
-/* Wait for the previous write to a RTC register to complete.
+/**
+ *     bfin_rtc_sync_pending - make sure pending writes have complete
+ *
+ * Wait for the previous write to a RTC register to complete.
  * Unfortunately, we can't sleep here as that introduces a race condition when
  * turning on interrupt events.  Consider this:
  *  - process sets alarm
@@ -112,188 +114,202 @@ static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm)
  * If anyone can point out the obvious solution here, i'm listening :).  This
  * shouldn't be an issue on an SMP or preempt system as this function should
  * only be called with the rtc lock held.
+ *
+ * Other options:
+ *  - disable PREN so the sync happens at 32.768kHZ ... but this changes the
+ *    inc rate for all RTC registers from 1HZ to 32.768kHZ ...
+ *  - use the write complete IRQ
  */
-static void rtc_bfin_sync_pending(void)
+/*
+static void bfin_rtc_sync_pending_polled(void)
 {
-       stampit();
-       while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) {
+       while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE))
                if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING))
                        break;
-       }
        bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
 }
+*/
+static DECLARE_COMPLETION(bfin_write_complete);
+static void bfin_rtc_sync_pending(struct device *dev)
+{
+       dev_dbg_stamp(dev);
+       while (bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING)
+               wait_for_completion_timeout(&bfin_write_complete, HZ * 5);
+       dev_dbg_stamp(dev);
+}
 
-static void rtc_bfin_reset(struct bfin_rtc *rtc)
+/**
+ *     bfin_rtc_reset - set RTC to sane/known state
+ *
+ * Initialize the RTC.  Enable pre-scaler to scale RTC clock
+ * to 1Hz and clear interrupt/status registers.
+ */
+static void bfin_rtc_reset(struct device *dev)
 {
-       /* Initialize the RTC. Enable pre-scaler to scale RTC clock
-        * to 1Hz and clear interrupt/status registers. */
-       spin_lock_irq(&rtc->lock);
-       rtc_bfin_sync_pending();
+       struct bfin_rtc *rtc = dev_get_drvdata(dev);
+       dev_dbg_stamp(dev);
+       bfin_rtc_sync_pending(dev);
        bfin_write_RTC_PREN(0x1);
-       bfin_write_RTC_ICTL(0);
+       bfin_write_RTC_ICTL(RTC_ISTAT_WRITE_COMPLETE);
        bfin_write_RTC_SWCNT(0);
        bfin_write_RTC_ALARM(0);
        bfin_write_RTC_ISTAT(0xFFFF);
-       spin_unlock_irq(&rtc->lock);
+       rtc->rtc_wrote_regs = 0;
 }
 
+/**
+ *     bfin_rtc_interrupt - handle interrupt from RTC
+ *
+ * Since we handle all RTC events here, we have to make sure the requested
+ * interrupt is enabled (in RTC_ICTL) as the event status register (RTC_ISTAT)
+ * always gets updated regardless of the interrupt being enabled.  So when one
+ * even we care about (e.g. stopwatch) goes off, we don't want to turn around
+ * and say that other events have happened as well (e.g. second).  We do not
+ * have to worry about pending writes to the RTC_ICTL register as interrupts
+ * only fire if they are enabled in the RTC_ICTL register.
+ */
 static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id)
 {
-       struct platform_device *pdev = to_platform_device(dev_id);
-       struct bfin_rtc *rtc = platform_get_drvdata(pdev);
+       struct device *dev = dev_id;
+       struct bfin_rtc *rtc = dev_get_drvdata(dev);
        unsigned long events = 0;
-       u16 rtc_istat;
-
-       stampit();
+       bool write_complete = false;
+       u16 rtc_istat, rtc_ictl;
 
-       spin_lock_irq(&rtc->lock);
+       dev_dbg_stamp(dev);
 
        rtc_istat = bfin_read_RTC_ISTAT();
+       rtc_ictl = bfin_read_RTC_ICTL();
 
-       if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
-               bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
-               events |= RTC_AF | RTC_IRQF;
+       if (rtc_istat & RTC_ISTAT_WRITE_COMPLETE) {
+               bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
+               write_complete = true;
+               complete(&bfin_write_complete);
        }
 
-       if (rtc_istat & RTC_ISTAT_STOPWATCH) {
-               bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
-               events |= RTC_PF | RTC_IRQF;
-               bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+       if (rtc_ictl & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+               if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+                       bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
+                       events |= RTC_AF | RTC_IRQF;
+               }
        }
 
-       if (rtc_istat & RTC_ISTAT_SEC) {
-               bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
-               events |= RTC_UF | RTC_IRQF;
+       if (rtc_ictl & RTC_ISTAT_STOPWATCH) {
+               if (rtc_istat & RTC_ISTAT_STOPWATCH) {
+                       bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+                       events |= RTC_PF | RTC_IRQF;
+                       bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+               }
        }
 
-       rtc_update_irq(rtc->rtc_dev, 1, events);
+       if (rtc_ictl & RTC_ISTAT_SEC) {
+               if (rtc_istat & RTC_ISTAT_SEC) {
+                       bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
+                       events |= RTC_UF | RTC_IRQF;
+               }
+       }
 
-       spin_unlock_irq(&rtc->lock);
+       if (events)
+               rtc_update_irq(rtc->rtc_dev, 1, events);
 
-       return IRQ_HANDLED;
+       if (write_complete || events)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
 }
 
 static int bfin_rtc_open(struct device *dev)
 {
-       struct bfin_rtc *rtc = dev_get_drvdata(dev);
        int ret;
 
-       stampit();
+       dev_dbg_stamp(dev);
 
-       ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_DISABLED, "rtc-bfin", dev);
-       if (unlikely(ret)) {
-               dev_err(dev, "request RTC IRQ failed with %d\n", ret);
-               return ret;
-       }
-
-       rtc_bfin_reset(rtc);
+       ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, to_platform_device(dev)->name, dev);
+       if (!ret)
+               bfin_rtc_reset(dev);
 
        return ret;
 }
 
 static void bfin_rtc_release(struct device *dev)
 {
-       struct bfin_rtc *rtc = dev_get_drvdata(dev);
-       stampit();
-       rtc_bfin_reset(rtc);
+       dev_dbg_stamp(dev);
+       bfin_rtc_reset(dev);
        free_irq(IRQ_RTC, dev);
 }
 
+static void bfin_rtc_int_set(struct bfin_rtc *rtc, u16 rtc_int)
+{
+       bfin_write_RTC_ISTAT(rtc_int);
+       bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | rtc_int);
+}
+static void bfin_rtc_int_clear(struct bfin_rtc *rtc, u16 rtc_int)
+{
+       bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & rtc_int);
+}
+static void bfin_rtc_int_set_alarm(struct bfin_rtc *rtc)
+{
+       /* Blackfin has different bits for whether the alarm is
+        * more than 24 hours away.
+        */
+       bfin_rtc_int_set(rtc, (rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY));
+}
 static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
+       int ret = 0;
+
+       dev_dbg_stamp(dev);
 
-       stampit();
+       bfin_rtc_sync_pending(dev);
 
        switch (cmd) {
        case RTC_PIE_ON:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_set(rtc, RTC_ISTAT_STOPWATCH);
                bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_STOPWATCH);
-               spin_unlock_irq(&rtc->lock);
-               return 0;
+               break;
        case RTC_PIE_OFF:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_SWCNT(0);
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_STOPWATCH);
-               spin_unlock_irq(&rtc->lock);
-               return 0;
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_clear(rtc, ~RTC_ISTAT_STOPWATCH);
+               break;
 
        case RTC_UIE_ON:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_SEC);
-               spin_unlock_irq(&rtc->lock);
-               return 0;
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_set(rtc, RTC_ISTAT_SEC);
+               break;
        case RTC_UIE_OFF:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_SEC);
-               spin_unlock_irq(&rtc->lock);
-               return 0;
-
-       case RTC_AIE_ON: {
-               unsigned long rtc_alarm;
-               u16 which_alarm;
-               int ret = 0;
-
-               stampit();
-
-               spin_lock_irq(&rtc->lock);
-
-               rtc_bfin_sync_pending();
-               if (rtc->rtc_alarm.tm_yday == -1) {
-                       struct rtc_time now;
-                       rtc_bfin_to_tm(bfin_read_RTC_STAT(), &now);
-                       now.tm_sec = rtc->rtc_alarm.tm_sec;
-                       now.tm_min = rtc->rtc_alarm.tm_min;
-                       now.tm_hour = rtc->rtc_alarm.tm_hour;
-                       ret = rtc_tm_to_time(&now, &rtc_alarm);
-                       which_alarm = RTC_ISTAT_ALARM;
-               } else {
-                       ret = rtc_tm_to_time(&rtc->rtc_alarm, &rtc_alarm);
-                       which_alarm = RTC_ISTAT_ALARM_DAY;
-               }
-               if (ret == 0) {
-                       bfin_write_RTC_ISTAT(which_alarm);
-                       bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
-                       bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | which_alarm);
-               }
-
-               spin_unlock_irq(&rtc->lock);
-
-               return ret;
-       }
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_clear(rtc, ~RTC_ISTAT_SEC);
+               break;
+
+       case RTC_AIE_ON:
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_set_alarm(rtc);
+               break;
        case RTC_AIE_OFF:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
-               spin_unlock_irq(&rtc->lock);
-               return 0;
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_clear(rtc, ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+               break;
+
+       default:
+               dev_dbg_stamp(dev);
+               ret = -ENOIOCTLCMD;
        }
 
-       return -ENOIOCTLCMD;
+       return ret;
 }
 
 static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
 
-       stampit();
+       dev_dbg_stamp(dev);
+
+       if (rtc->rtc_wrote_regs & 0x1)
+               bfin_rtc_sync_pending(dev);
 
-       spin_lock_irq(&rtc->lock);
-       rtc_bfin_sync_pending();
        rtc_bfin_to_tm(bfin_read_RTC_STAT(), tm);
-       spin_unlock_irq(&rtc->lock);
 
        return 0;
 }
@@ -304,64 +320,79 @@ static int bfin_rtc_set_time(struct device *dev, struct rtc_time *tm)
        int ret;
        unsigned long now;
 
-       stampit();
-
-       spin_lock_irq(&rtc->lock);
+       dev_dbg_stamp(dev);
 
        ret = rtc_tm_to_time(tm, &now);
        if (ret == 0) {
-               rtc_bfin_sync_pending();
+               if (rtc->rtc_wrote_regs & 0x1)
+                       bfin_rtc_sync_pending(dev);
                bfin_write_RTC_STAT(rtc_time_to_bfin(now));
+               rtc->rtc_wrote_regs = 0x1;
        }
 
-       spin_unlock_irq(&rtc->lock);
-
        return ret;
 }
 
 static int bfin_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
-       stampit();
-       memcpy(&alrm->time, &rtc->rtc_alarm, sizeof(struct rtc_time));
-       alrm->pending = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+       dev_dbg_stamp(dev);
+       alrm->time = rtc->rtc_alarm;
+       bfin_rtc_sync_pending(dev);
+       alrm->enabled = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
        return 0;
 }
 
 static int bfin_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
-       stampit();
-       memcpy(&rtc->rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+       unsigned long rtc_alarm;
+
+       dev_dbg_stamp(dev);
+
+       if (rtc_tm_to_time(&alrm->time, &rtc_alarm))
+               return -EINVAL;
+
+       rtc->rtc_alarm = alrm->time;
+
+       bfin_rtc_sync_pending(dev);
+       bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
+       if (alrm->enabled)
+               bfin_rtc_int_set_alarm(rtc);
+
        return 0;
 }
 
 static int bfin_rtc_proc(struct device *dev, struct seq_file *seq)
 {
-#define yesno(x) (x ? "yes" : "no")
+#define yesno(x) ((x) ? "yes" : "no")
        u16 ictl = bfin_read_RTC_ICTL();
-       stampit();
-       seq_printf(seq, "alarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM));
-       seq_printf(seq, "wkalarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM_DAY));
-       seq_printf(seq, "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_SEC));
-       seq_printf(seq, "periodic_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_STOPWATCH));
-#ifdef DEBUG
-       seq_printf(seq, "RTC_STAT\t: 0x%08X\n", bfin_read_RTC_STAT());
-       seq_printf(seq, "RTC_ICTL\t: 0x%04X\n", bfin_read_RTC_ICTL());
-       seq_printf(seq, "RTC_ISTAT\t: 0x%04X\n", bfin_read_RTC_ISTAT());
-       seq_printf(seq, "RTC_SWCNT\t: 0x%04X\n", bfin_read_RTC_SWCNT());
-       seq_printf(seq, "RTC_ALARM\t: 0x%08X\n", bfin_read_RTC_ALARM());
-       seq_printf(seq, "RTC_PREN\t: 0x%04X\n", bfin_read_RTC_PREN());
-#endif
+       dev_dbg_stamp(dev);
+       seq_printf(seq,
+               "alarm_IRQ\t: %s\n"
+               "wkalarm_IRQ\t: %s\n"
+               "seconds_IRQ\t: %s\n"
+               "periodic_IRQ\t: %s\n",
+               yesno(ictl & RTC_ISTAT_ALARM),
+               yesno(ictl & RTC_ISTAT_ALARM_DAY),
+               yesno(ictl & RTC_ISTAT_SEC),
+               yesno(ictl & RTC_ISTAT_STOPWATCH));
        return 0;
+#undef yesno
 }
 
+/**
+ *     bfin_irq_set_freq - make sure hardware supports requested freq
+ *     @dev: pointer to RTC device structure
+ *     @freq: requested frequency rate
+ *
+ *     The Blackfin RTC can only generate periodic events at 1 per
+ *     second (1 Hz), so reject any attempt at changing it.
+ */
 static int bfin_irq_set_freq(struct device *dev, int freq)
 {
-       struct bfin_rtc *rtc = dev_get_drvdata(dev);
-       stampit();
-       rtc->rtc_dev->irq_freq = freq;
-       return 0;
+       dev_dbg_stamp(dev);
+       return -ENOTTY;
 }
 
 static struct rtc_class_ops bfin_rtc_ops = {
@@ -381,27 +412,24 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
        struct bfin_rtc *rtc;
        int ret = 0;
 
-       stampit();
+       dev_dbg_stamp(&pdev->dev);
 
        rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
        if (unlikely(!rtc))
                return -ENOMEM;
 
-       spin_lock_init(&rtc->lock);
-
        rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE);
        if (unlikely(IS_ERR(rtc))) {
                ret = PTR_ERR(rtc->rtc_dev);
                goto err;
        }
-       rtc->rtc_dev->irq_freq = 0;
-       rtc->rtc_dev->max_user_freq = (2 << 16); /* stopwatch is an unsigned 16 bit reg */
+       rtc->rtc_dev->irq_freq = 1;
 
        platform_set_drvdata(pdev, rtc);
 
        return 0;
 
-err:
+ err:
        kfree(rtc);
        return ret;
 }
@@ -428,7 +456,6 @@ static struct platform_driver bfin_rtc_driver = {
 
 static int __init bfin_rtc_init(void)
 {
-       stampit();
        return platform_driver_register(&bfin_rtc_driver);
 }
 
index 29cf1457ca10f507104a5a54d9fedd88f0544a95..e059f94c79eb2663632feff0e7a990d7aaa0a42c 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/mod_devicetable.h>
 
+#ifdef CONFIG_HPET_EMULATE_RTC
+#include <asm/hpet.h>
+#endif
+
 /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
 #include <asm-generic/rtc.h>
 
+#ifndef CONFIG_HPET_EMULATE_RTC
+#define is_hpet_enabled()                      0
+#define hpet_set_alarm_time(hrs, min, sec)     do { } while (0)
+#define hpet_set_periodic_freq(arg)            0
+#define hpet_mask_rtc_irq_bit(arg)             do { } while (0)
+#define hpet_set_rtc_irq_bit(arg)              do { } while (0)
+#define hpet_rtc_timer_init()                  do { } while (0)
+#define hpet_register_irq_handler(h)           0
+#define hpet_unregister_irq_handler(h)         do { } while (0)
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+#endif
 
 struct cmos_rtc {
        struct rtc_device       *rtc;
@@ -199,6 +214,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        sec = t->time.tm_sec;
        sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
 
+       hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
        spin_lock_irq(&rtc_lock);
 
        /* next rtc irq must not be from previous alarm setting */
@@ -252,7 +268,8 @@ static int cmos_irq_set_freq(struct device *dev, int freq)
        f = 16 - f;
 
        spin_lock_irqsave(&rtc_lock, flags);
-       CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
+       if (!hpet_set_periodic_freq(freq))
+               CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
        spin_unlock_irqrestore(&rtc_lock, flags);
 
        return 0;
@@ -314,28 +331,37 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        switch (cmd) {
        case RTC_AIE_OFF:       /* alarm off */
                rtc_control &= ~RTC_AIE;
+               hpet_mask_rtc_irq_bit(RTC_AIE);
                break;
        case RTC_AIE_ON:        /* alarm on */
                rtc_control |= RTC_AIE;
+               hpet_set_rtc_irq_bit(RTC_AIE);
                break;
        case RTC_UIE_OFF:       /* update off */
                rtc_control &= ~RTC_UIE;
+               hpet_mask_rtc_irq_bit(RTC_UIE);
                break;
        case RTC_UIE_ON:        /* update on */
                rtc_control |= RTC_UIE;
+               hpet_set_rtc_irq_bit(RTC_UIE);
                break;
        case RTC_PIE_OFF:       /* periodic off */
                rtc_control &= ~RTC_PIE;
+               hpet_mask_rtc_irq_bit(RTC_PIE);
                break;
        case RTC_PIE_ON:        /* periodic on */
                rtc_control |= RTC_PIE;
+               hpet_set_rtc_irq_bit(RTC_PIE);
                break;
        }
-       CMOS_WRITE(rtc_control, RTC_CONTROL);
+       if (!is_hpet_enabled())
+               CMOS_WRITE(rtc_control, RTC_CONTROL);
+
        rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
        rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
        if (is_intr(rtc_intr))
                rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
        spin_unlock_irqrestore(&rtc_lock, flags);
        return 0;
 }
@@ -393,15 +419,111 @@ static const struct rtc_class_ops cmos_rtc_ops = {
 
 /*----------------------------------------------------------------*/
 
+/*
+ * All these chips have at least 64 bytes of address space, shared by
+ * RTC registers and NVRAM.  Most of those bytes of NVRAM are used
+ * by boot firmware.  Modern chips have 128 or 256 bytes.
+ */
+
+#define NVRAM_OFFSET   (RTC_REG_D + 1)
+
+static ssize_t
+cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       int     retval;
+
+       if (unlikely(off >= attr->size))
+               return 0;
+       if ((off + count) > attr->size)
+               count = attr->size - off;
+
+       spin_lock_irq(&rtc_lock);
+       for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++)
+               *buf++ = CMOS_READ(off);
+       spin_unlock_irq(&rtc_lock);
+
+       return retval;
+}
+
+static ssize_t
+cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct cmos_rtc *cmos;
+       int             retval;
+
+       cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
+       if (unlikely(off >= attr->size))
+               return -EFBIG;
+       if ((off + count) > attr->size)
+               count = attr->size - off;
+
+       /* NOTE:  on at least PCs and Ataris, the boot firmware uses a
+        * checksum on part of the NVRAM data.  That's currently ignored
+        * here.  If userspace is smart enough to know what fields of
+        * NVRAM to update, updating checksums is also part of its job.
+        */
+       spin_lock_irq(&rtc_lock);
+       for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) {
+               /* don't trash RTC registers */
+               if (off == cmos->day_alrm
+                               || off == cmos->mon_alrm
+                               || off == cmos->century)
+                       buf++;
+               else
+                       CMOS_WRITE(*buf++, off);
+       }
+       spin_unlock_irq(&rtc_lock);
+
+       return retval;
+}
+
+static struct bin_attribute nvram = {
+       .attr = {
+               .name   = "nvram",
+               .mode   = S_IRUGO | S_IWUSR,
+               .owner  = THIS_MODULE,
+       },
+
+       .read   = cmos_nvram_read,
+       .write  = cmos_nvram_write,
+       /* size gets set up later */
+};
+
+/*----------------------------------------------------------------*/
+
 static struct cmos_rtc cmos_rtc;
 
 static irqreturn_t cmos_interrupt(int irq, void *p)
 {
        u8              irqstat;
+       u8              rtc_control;
 
        spin_lock(&rtc_lock);
-       irqstat = CMOS_READ(RTC_INTR_FLAGS);
-       irqstat &= (CMOS_READ(RTC_CONTROL) & RTC_IRQMASK) | RTC_IRQF;
+       /*
+        * In this case it is HPET RTC interrupt handler
+        * calling us, with the interrupt information
+        * passed as arg1, instead of irq.
+        */
+       if (is_hpet_enabled())
+               irqstat = (unsigned long)irq & 0xF0;
+       else {
+               irqstat = CMOS_READ(RTC_INTR_FLAGS);
+               rtc_control = CMOS_READ(RTC_CONTROL);
+               irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+       }
+
+       /* All Linux RTC alarms should be treated as if they were oneshot.
+        * Similar code may be needed in system wakeup paths, in case the
+        * alarm woke the system.
+        */
+       if (irqstat & RTC_AIE) {
+               rtc_control = CMOS_READ(RTC_CONTROL);
+               rtc_control &= ~RTC_AIE;
+               CMOS_WRITE(rtc_control, RTC_CONTROL);
+               CMOS_READ(RTC_INTR_FLAGS);
+       }
        spin_unlock(&rtc_lock);
 
        if (is_intr(irqstat)) {
@@ -412,11 +534,9 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
 }
 
 #ifdef CONFIG_PNP
-#define        is_pnp()        1
 #define        INITSECTION
 
 #else
-#define        is_pnp()        0
 #define        INITSECTION     __init
 #endif
 
@@ -426,6 +546,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
        struct cmos_rtc_board_info      *info = dev->platform_data;
        int                             retval = 0;
        unsigned char                   rtc_control;
+       unsigned                        address_space;
 
        /* there can be only one ... */
        if (cmos_rtc.dev)
@@ -450,15 +571,36 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
        cmos_rtc.irq = rtc_irq;
        cmos_rtc.iomem = ports;
 
+       /* Heuristic to deduce NVRAM size ... do what the legacy NVRAM
+        * driver did, but don't reject unknown configs.   Old hardware
+        * won't address 128 bytes, and for now we ignore the way newer
+        * chips can address 256 bytes (using two more i/o ports).
+        */
+#if    defined(CONFIG_ATARI)
+       address_space = 64;
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+       address_space = 128;
+#else
+#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
+       address_space = 128;
+#endif
+
        /* For ACPI systems extension info comes from the FADT.  On others,
         * board specific setup provides it as appropriate.  Systems where
         * the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and
         * some almost-clones) can provide hooks to make that behave.
+        *
+        * Note that ACPI doesn't preclude putting these registers into
+        * "extended" areas of the chip, including some that we won't yet
+        * expect CMOS_READ and friends to handle.
         */
        if (info) {
-               cmos_rtc.day_alrm = info->rtc_day_alarm;
-               cmos_rtc.mon_alrm = info->rtc_mon_alarm;
-               cmos_rtc.century = info->rtc_century;
+               if (info->rtc_day_alarm && info->rtc_day_alarm < 128)
+                       cmos_rtc.day_alrm = info->rtc_day_alarm;
+               if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128)
+                       cmos_rtc.mon_alrm = info->rtc_mon_alarm;
+               if (info->rtc_century && info->rtc_century < 128)
+                       cmos_rtc.century = info->rtc_century;
 
                if (info->wake_on && info->wake_off) {
                        cmos_rtc.wake_on = info->wake_on;
@@ -485,8 +627,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
         * doesn't use 32KHz here ... for portability we might need to
         * do something about other clock frequencies.
         */
-       CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
        cmos_rtc.rtc->irq_freq = 1024;
+       if (!hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq))
+               CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
 
        /* disable irqs.
         *
@@ -509,19 +652,39 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                goto cleanup1;
        }
 
-       if (is_valid_irq(rtc_irq))
-               retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED,
-                               cmos_rtc.rtc->dev.bus_id,
+       if (is_valid_irq(rtc_irq)) {
+               irq_handler_t rtc_cmos_int_handler;
+
+               if (is_hpet_enabled()) {
+                       int err;
+
+                       rtc_cmos_int_handler = hpet_rtc_interrupt;
+                       err = hpet_register_irq_handler(cmos_interrupt);
+                       if (err != 0) {
+                               printk(KERN_WARNING "hpet_register_irq_handler "
+                                               " failed in rtc_init().");
+                               goto cleanup1;
+                       }
+               } else
+                       rtc_cmos_int_handler = cmos_interrupt;
+
+               retval = request_irq(rtc_irq, rtc_cmos_int_handler,
+                               IRQF_DISABLED, cmos_rtc.rtc->dev.bus_id,
                                cmos_rtc.rtc);
-       if (retval < 0) {
-               dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
-               goto cleanup1;
+               if (retval < 0) {
+                       dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
+                       goto cleanup1;
+               }
        }
+       hpet_rtc_timer_init();
 
-       /* REVISIT optionally make 50 or 114 bytes NVRAM available,
-        * like rtc-ds1553, rtc-ds1742 ... this will often include
-        * registers for century, and day/month alarm.
-        */
+       /* export at least the first block of NVRAM */
+       nvram.size = address_space - NVRAM_OFFSET;
+       retval = sysfs_create_bin_file(&dev->kobj, &nvram);
+       if (retval < 0) {
+               dev_dbg(dev, "can't create nvram file? %d\n", retval);
+               goto cleanup2;
+       }
 
        pr_info("%s: alarms up to one %s%s\n",
                        cmos_rtc.rtc->dev.bus_id,
@@ -536,6 +699,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 
        return 0;
 
+cleanup2:
+       if (is_valid_irq(rtc_irq))
+               free_irq(rtc_irq, cmos_rtc.rtc);
 cleanup1:
        cmos_rtc.dev = NULL;
        rtc_device_unregister(cmos_rtc.rtc);
@@ -563,8 +729,12 @@ static void __exit cmos_do_remove(struct device *dev)
 
        cmos_do_shutdown();
 
-       if (is_valid_irq(cmos->irq))
+       sysfs_remove_bin_file(&dev->kobj, &nvram);
+
+       if (is_valid_irq(cmos->irq)) {
                free_irq(cmos->irq, cmos->rtc);
+               hpet_unregister_irq_handler(cmos_interrupt);
+       }
 
        rtc_device_unregister(cmos->rtc);
        cmos->rtc = NULL;
@@ -659,9 +829,12 @@ static int cmos_resume(struct device *dev)
 
 /*----------------------------------------------------------------*/
 
-/* The "CMOS" RTC normally lives on the platform_bus.  On ACPI systems,
- * the device node will always be created as a PNPACPI device.  Plus
- * pre-ACPI PCs probably list it in the PNPBIOS tables.
+/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus.
+ * ACPI systems always list these as PNPACPI devices, and pre-ACPI PCs
+ * probably list them in similar PNPBIOS tables; so PNP is more common.
+ *
+ * We don't use legacy "poke at the hardware" probing.  Ancient PCs that
+ * predate even PNPBIOS should set up platform_bus devices.
  */
 
 #ifdef CONFIG_PNP
index 025c60a17a4a3c9841d4105bf0344a92f9c31510..90dfa0df747acb9314b4ed115c2eec0dee1eae0d 100644 (file)
@@ -246,6 +246,15 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
        /* if the driver does not provide the ioctl interface
         * or if that particular ioctl was not implemented
         * (-ENOIOCTLCMD), we will try to emulate here.
+        *
+        * Drivers *SHOULD NOT* provide ioctl implementations
+        * for these requests.  Instead, provide methods to
+        * support the following code, so that the RTC's main
+        * features are accessible without using ioctls.
+        *
+        * RTC and alarm times will be in UTC, by preference,
+        * but dual-booting with MS-Windows implies RTCs must
+        * use the local wall clock time.
         */
 
        switch (cmd) {
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
new file mode 100644 (file)
index 0000000..7b002ce
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Dallas DS1302 RTC Support
+ *
+ *  Copyright (C) 2002  David McCullough
+ *  Copyright (C) 2003 - 2007  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/bcd.h>
+#include <asm/rtc.h>
+
+#define DRV_NAME       "rtc-ds1302"
+#define DRV_VERSION    "0.1.0"
+
+#define        RTC_CMD_READ    0x81            /* Read command */
+#define        RTC_CMD_WRITE   0x80            /* Write command */
+
+#define RTC_ADDR_RAM0  0x20            /* Address of RAM0 */
+#define RTC_ADDR_TCR   0x08            /* Address of trickle charge register */
+#define        RTC_ADDR_YEAR   0x06            /* Address of year register */
+#define        RTC_ADDR_DAY    0x05            /* Address of day of week register */
+#define        RTC_ADDR_MON    0x04            /* Address of month register */
+#define        RTC_ADDR_DATE   0x03            /* Address of day of month register */
+#define        RTC_ADDR_HOUR   0x02            /* Address of hour register */
+#define        RTC_ADDR_MIN    0x01            /* Address of minute register */
+#define        RTC_ADDR_SEC    0x00            /* Address of second register */
+
+#define        RTC_RESET       0x1000
+#define        RTC_IODATA      0x0800
+#define        RTC_SCLK        0x0400
+
+#ifdef CONFIG_SH_SECUREEDGE5410
+#include <asm/snapgear.h>
+#define set_dp(x)      SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
+#define get_dp()       SECUREEDGE_READ_IOPORT()
+#else
+#error "Add support for your platform"
+#endif
+
+struct ds1302_rtc {
+       struct rtc_device *rtc_dev;
+       spinlock_t lock;
+};
+
+static void ds1302_sendbits(unsigned int val)
+{
+       int i;
+
+       for (i = 8; (i); i--, val >>= 1) {
+               set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ?
+                       RTC_IODATA : 0));
+               set_dp(get_dp() | RTC_SCLK);    /* clock high */
+               set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+       }
+}
+
+static unsigned int ds1302_recvbits(void)
+{
+       unsigned int val;
+       int i;
+
+       for (i = 0, val = 0; (i < 8); i++) {
+               val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i);
+               set_dp(get_dp() | RTC_SCLK);    /* clock high */
+               set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+       }
+
+       return val;
+}
+
+static unsigned int ds1302_readbyte(unsigned int addr)
+{
+       unsigned int val;
+
+       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+
+       set_dp(get_dp() | RTC_RESET);
+       ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
+       val = ds1302_recvbits();
+       set_dp(get_dp() & ~RTC_RESET);
+
+       return val;
+}
+
+static void ds1302_writebyte(unsigned int addr, unsigned int val)
+{
+       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+       set_dp(get_dp() | RTC_RESET);
+       ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
+       ds1302_sendbits(val);
+       set_dp(get_dp() & ~RTC_RESET);
+}
+
+static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+
+       spin_lock_irq(&rtc->lock);
+
+       tm->tm_sec      = BCD2BIN(ds1302_readbyte(RTC_ADDR_SEC));
+       tm->tm_min      = BCD2BIN(ds1302_readbyte(RTC_ADDR_MIN));
+       tm->tm_hour     = BCD2BIN(ds1302_readbyte(RTC_ADDR_HOUR));
+       tm->tm_wday     = BCD2BIN(ds1302_readbyte(RTC_ADDR_DAY));
+       tm->tm_mday     = BCD2BIN(ds1302_readbyte(RTC_ADDR_DATE));
+       tm->tm_mon      = BCD2BIN(ds1302_readbyte(RTC_ADDR_MON)) - 1;
+       tm->tm_year     = BCD2BIN(ds1302_readbyte(RTC_ADDR_YEAR));
+
+       if (tm->tm_year < 70)
+               tm->tm_year += 100;
+
+       spin_unlock_irq(&rtc->lock);
+
+       dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+               "mday=%d, mon=%d, year=%d, wday=%d\n",
+               __FUNCTION__,
+               tm->tm_sec, tm->tm_min, tm->tm_hour,
+               tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
+
+       if (rtc_valid_tm(tm) < 0)
+               dev_err(dev, "invalid date\n");
+
+       return 0;
+}
+
+static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+
+       spin_lock_irq(&rtc->lock);
+
+       /* Stop RTC */
+       ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
+
+       ds1302_writebyte(RTC_ADDR_SEC, BIN2BCD(tm->tm_sec));
+       ds1302_writebyte(RTC_ADDR_MIN, BIN2BCD(tm->tm_min));
+       ds1302_writebyte(RTC_ADDR_HOUR, BIN2BCD(tm->tm_hour));
+       ds1302_writebyte(RTC_ADDR_DAY, BIN2BCD(tm->tm_wday));
+       ds1302_writebyte(RTC_ADDR_DATE, BIN2BCD(tm->tm_mday));
+       ds1302_writebyte(RTC_ADDR_MON, BIN2BCD(tm->tm_mon + 1));
+       ds1302_writebyte(RTC_ADDR_YEAR, BIN2BCD(tm->tm_year % 100));
+
+       /* Start RTC */
+       ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
+
+       spin_unlock_irq(&rtc->lock);
+
+       return 0;
+}
+
+static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd,
+                           unsigned long arg)
+{
+       switch (cmd) {
+#ifdef RTC_SET_CHARGE
+       case RTC_SET_CHARGE:
+       {
+               struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+               int tcs_val;
+
+               if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int)))
+                       return -EFAULT;
+
+               spin_lock_irq(&rtc->lock);
+               ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf));
+               spin_unlock_irq(&rtc->lock);
+               return 0;
+       }
+#endif
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+static struct rtc_class_ops ds1302_rtc_ops = {
+       .read_time      = ds1302_rtc_read_time,
+       .set_time       = ds1302_rtc_set_time,
+       .ioctl          = ds1302_rtc_ioctl,
+};
+
+static int __devinit ds1302_rtc_probe(struct platform_device *pdev)
+{
+       struct ds1302_rtc *rtc;
+       int ret;
+
+       /* Reset */
+       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+
+       /* Write a magic value to the DS1302 RAM, and see if it sticks. */
+       ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
+       if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42)
+               return -ENODEV;
+
+       rtc = kzalloc(sizeof(struct ds1302_rtc), GFP_KERNEL);
+       if (unlikely(!rtc))
+               return -ENOMEM;
+
+       spin_lock_init(&rtc->lock);
+       rtc->rtc_dev = rtc_device_register("ds1302", &pdev->dev,
+                                          &ds1302_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtc_dev)) {
+               ret = PTR_ERR(rtc->rtc_dev);
+               goto out;
+       }
+
+       platform_set_drvdata(pdev, rtc);
+
+       return 0;
+out:
+       kfree(rtc);
+       return ret;
+}
+
+static int __devexit ds1302_rtc_remove(struct platform_device *pdev)
+{
+       struct ds1302_rtc *rtc = platform_get_drvdata(pdev);
+
+       if (likely(rtc->rtc_dev))
+               rtc_device_unregister(rtc->rtc_dev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(rtc);
+
+       return 0;
+}
+
+static struct platform_driver ds1302_platform_driver = {
+       .driver         = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ds1302_rtc_probe,
+       .remove         = __devexit_p(ds1302_rtc_remove),
+};
+
+static int __init ds1302_rtc_init(void)
+{
+       return platform_driver_register(&ds1302_platform_driver);
+}
+
+static void __exit ds1302_rtc_exit(void)
+{
+       platform_driver_unregister(&ds1302_platform_driver);
+}
+
+module_init(ds1302_rtc_init);
+module_exit(ds1302_rtc_exit);
+
+MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Paul Mundt, David McCullough");
+MODULE_LICENSE("GPL v2");
index bc1c7fe94ad3eceaf352e49eb2e6843de924a6e5..f389a28720d2da4302c05a1ef56e2fc5530272a7 100644 (file)
@@ -256,7 +256,7 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
        struct i2c_msg          msg[2];
        int                     result;
 
-       client = to_i2c_client(container_of(kobj, struct device, kobj));
+       client = kobj_to_i2c_client(kobj);
        ds1307 = i2c_get_clientdata(client);
 
        if (unlikely(off >= NVRAM_SIZE))
@@ -294,7 +294,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
        u8                      buffer[NVRAM_SIZE + 1];
        int                     ret;
 
-       client = to_i2c_client(container_of(kobj, struct device, kobj));
+       client = kobj_to_i2c_client(kobj);
 
        if (unlikely(off >= NVRAM_SIZE))
                return -EFBIG;
@@ -412,11 +412,6 @@ read_rtc:
         */
        tmp = ds1307->regs[DS1307_REG_SECS];
        switch (ds1307->type) {
-       case ds_1340:
-               /* FIXME read register with DS1340_BIT_OSF, use that to
-                * trigger the "set time" warning (*after* restarting the
-                * oscillator!) instead of this weaker ds1307/m41t00 test.
-                */
        case ds_1307:
        case m41t00:
                /* clock halted?  turn it on, so clock can tick. */
@@ -440,6 +435,24 @@ read_rtc:
                        goto read_rtc;
                }
                break;
+       case ds_1340:
+               /* clock halted?  turn it on, so clock can tick. */
+               if (tmp & DS1340_BIT_nEOSC)
+                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+
+               tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
+               if (tmp < 0) {
+                       pr_debug("read error %d\n", tmp);
+                       err = -EIO;
+                       goto exit_free;
+               }
+
+               /* oscillator fault?  clear flag, and warn */
+               if (tmp & DS1340_BIT_OSF) {
+                       i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0);
+                       dev_warn(&client->dev, "SET TIME!\n");
+               }
+               break;
        case ds_1337:
        case ds_1339:
                break;
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
new file mode 100644 (file)
index 0000000..d74b808
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * An rtc driver for the Dallas DS1511
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ * Copyright (C) 2007 Andrew Sharp <andy.sharp@onstor.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Real time clock driver for the Dallas 1511 chip, which also
+ * contains a watchdog timer.  There is a tiny amount of code that
+ * platform code could use to mess with the watchdog device a little
+ * bit, but not a full watchdog driver.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.6"
+
+enum ds1511reg {
+       DS1511_SEC = 0x0,
+       DS1511_MIN = 0x1,
+       DS1511_HOUR = 0x2,
+       DS1511_DOW = 0x3,
+       DS1511_DOM = 0x4,
+       DS1511_MONTH = 0x5,
+       DS1511_YEAR = 0x6,
+       DS1511_CENTURY = 0x7,
+       DS1511_AM1_SEC = 0x8,
+       DS1511_AM2_MIN = 0x9,
+       DS1511_AM3_HOUR = 0xa,
+       DS1511_AM4_DATE = 0xb,
+       DS1511_WD_MSEC = 0xc,
+       DS1511_WD_SEC = 0xd,
+       DS1511_CONTROL_A = 0xe,
+       DS1511_CONTROL_B = 0xf,
+       DS1511_RAMADDR_LSB = 0x10,
+       DS1511_RAMDATA = 0x13
+};
+
+#define DS1511_BLF1    0x80
+#define DS1511_BLF2    0x40
+#define DS1511_PRS     0x20
+#define DS1511_PAB     0x10
+#define DS1511_TDF     0x08
+#define DS1511_KSF     0x04
+#define DS1511_WDF     0x02
+#define DS1511_IRQF    0x01
+#define DS1511_TE      0x80
+#define DS1511_CS      0x40
+#define DS1511_BME     0x20
+#define DS1511_TPE     0x10
+#define DS1511_TIE     0x08
+#define DS1511_KIE     0x04
+#define DS1511_WDE     0x02
+#define DS1511_WDS     0x01
+#define DS1511_RAM_MAX 0xff
+
+#define RTC_CMD                DS1511_CONTROL_B
+#define RTC_CMD1       DS1511_CONTROL_A
+
+#define RTC_ALARM_SEC  DS1511_AM1_SEC
+#define RTC_ALARM_MIN  DS1511_AM2_MIN
+#define RTC_ALARM_HOUR DS1511_AM3_HOUR
+#define RTC_ALARM_DATE DS1511_AM4_DATE
+
+#define RTC_SEC                DS1511_SEC
+#define RTC_MIN                DS1511_MIN
+#define RTC_HOUR       DS1511_HOUR
+#define RTC_DOW                DS1511_DOW
+#define RTC_DOM                DS1511_DOM
+#define RTC_MON                DS1511_MONTH
+#define RTC_YEAR       DS1511_YEAR
+#define RTC_CENTURY    DS1511_CENTURY
+
+#define RTC_TIE        DS1511_TIE
+#define RTC_TE DS1511_TE
+
+struct rtc_plat_data {
+       struct rtc_device *rtc;
+       void __iomem *ioaddr;           /* virtual base address */
+       unsigned long baseaddr;         /* physical base address */
+       int size;                               /* amount of memory mapped */
+       int irq;
+       unsigned int irqen;
+       int alrm_sec;
+       int alrm_min;
+       int alrm_hour;
+       int alrm_mday;
+};
+
+static DEFINE_SPINLOCK(ds1511_lock);
+
+static __iomem char *ds1511_base;
+static u32 reg_spacing = 1;
+
+ static noinline void
+rtc_write(uint8_t val, uint32_t reg)
+{
+       writeb(val, ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_write_alarm(uint8_t val, enum ds1511reg reg)
+{
+       rtc_write((val | 0x80), reg);
+}
+
+ static noinline uint8_t
+rtc_read(enum ds1511reg reg)
+{
+       return readb(ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_disable_update(void)
+{
+       rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);
+}
+
+ static void
+rtc_enable_update(void)
+{
+       rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
+}
+
+/*
+ * #define DS1511_WDOG_RESET_SUPPORT
+ *
+ * Uncomment this if you want to use these routines in
+ * some platform code.
+ */
+#ifdef DS1511_WDOG_RESET_SUPPORT
+/*
+ * just enough code to set the watchdog timer so that it
+ * will reboot the system
+ */
+ void
+ds1511_wdog_set(unsigned long deciseconds)
+{
+       /*
+        * the wdog timer can take 99.99 seconds
+        */
+       deciseconds %= 10000;
+       /*
+        * set the wdog values in the wdog registers
+        */
+       rtc_write(BIN2BCD(deciseconds % 100), DS1511_WD_MSEC);
+       rtc_write(BIN2BCD(deciseconds / 100), DS1511_WD_SEC);
+       /*
+        * set wdog enable and wdog 'steering' bit to issue a reset
+        */
+       rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD);
+}
+
+ void
+ds1511_wdog_disable(void)
+{
+       /*
+        * clear wdog enable and wdog 'steering' bits
+        */
+       rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD);
+       /*
+        * clear the wdog counter
+        */
+       rtc_write(0, DS1511_WD_MSEC);
+       rtc_write(0, DS1511_WD_SEC);
+}
+#endif
+
+/*
+ * set the rtc chip's idea of the time.
+ * stupidly, some callers call with year unmolested;
+ * and some call with  year = year - 1900.  thanks.
+ */
+ int
+ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+       u8 mon, day, dow, hrs, min, sec, yrs, cen;
+       unsigned int flags;
+
+       /*
+        * won't have to change this for a while
+        */
+       if (rtc_tm->tm_year < 1900) {
+               rtc_tm->tm_year += 1900;
+       }
+
+       if (rtc_tm->tm_year < 1970) {
+               return -EINVAL;
+       }
+       yrs = rtc_tm->tm_year % 100;
+       cen = rtc_tm->tm_year / 100;
+       mon = rtc_tm->tm_mon + 1;   /* tm_mon starts at zero */
+       day = rtc_tm->tm_mday;
+       dow = rtc_tm->tm_wday & 0x7; /* automatic BCD */
+       hrs = rtc_tm->tm_hour;
+       min = rtc_tm->tm_min;
+       sec = rtc_tm->tm_sec;
+
+       if ((mon > 12) || (day == 0)) {
+               return -EINVAL;
+       }
+
+       if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) {
+               return -EINVAL;
+       }
+
+       if ((hrs >= 24) || (min >= 60) || (sec >= 60)) {
+               return -EINVAL;
+       }
+
+       /*
+        * each register is a different number of valid bits
+        */
+       sec = BIN2BCD(sec) & 0x7f;
+       min = BIN2BCD(min) & 0x7f;
+       hrs = BIN2BCD(hrs) & 0x3f;
+       day = BIN2BCD(day) & 0x3f;
+       mon = BIN2BCD(mon) & 0x1f;
+       yrs = BIN2BCD(yrs) & 0xff;
+       cen = BIN2BCD(cen) & 0xff;
+
+       spin_lock_irqsave(&ds1511_lock, flags);
+       rtc_disable_update();
+       rtc_write(cen, RTC_CENTURY);
+       rtc_write(yrs, RTC_YEAR);
+       rtc_write((rtc_read(RTC_MON) & 0xe0) | mon, RTC_MON);
+       rtc_write(day, RTC_DOM);
+       rtc_write(hrs, RTC_HOUR);
+       rtc_write(min, RTC_MIN);
+       rtc_write(sec, RTC_SEC);
+       rtc_write(dow, RTC_DOW);
+       rtc_enable_update();
+       spin_unlock_irqrestore(&ds1511_lock, flags);
+
+       return 0;
+}
+
+ int
+ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+       unsigned int century;
+       unsigned int flags;
+
+       spin_lock_irqsave(&ds1511_lock, flags);
+       rtc_disable_update();
+
+       rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f;
+       rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f;
+       rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f;
+       rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f;
+       rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7;
+       rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f;
+       rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f;
+       century = rtc_read(RTC_CENTURY);
+
+       rtc_enable_update();
+       spin_unlock_irqrestore(&ds1511_lock, flags);
+
+       rtc_tm->tm_sec = BCD2BIN(rtc_tm->tm_sec);
+       rtc_tm->tm_min = BCD2BIN(rtc_tm->tm_min);
+       rtc_tm->tm_hour = BCD2BIN(rtc_tm->tm_hour);
+       rtc_tm->tm_mday = BCD2BIN(rtc_tm->tm_mday);
+       rtc_tm->tm_wday = BCD2BIN(rtc_tm->tm_wday);
+       rtc_tm->tm_mon = BCD2BIN(rtc_tm->tm_mon);
+       rtc_tm->tm_year = BCD2BIN(rtc_tm->tm_year);
+       century = BCD2BIN(century) * 100;
+
+       /*
+        * Account for differences between how the RTC uses the values
+        * and how they are defined in a struct rtc_time;
+        */
+       century += rtc_tm->tm_year;
+       rtc_tm->tm_year = century - 1900;
+
+       rtc_tm->tm_mon--;
+
+       if (rtc_valid_tm(rtc_tm) < 0) {
+               dev_err(dev, "retrieved date/time is not valid.\n");
+               rtc_time_to_tm(0, rtc_tm);
+       }
+       return 0;
+}
+
+/*
+ * write the alarm register settings
+ *
+ * we only have the use to interrupt every second, otherwise
+ * known as the update interrupt, or the interrupt if the whole
+ * date/hours/mins/secs matches.  the ds1511 has many more
+ * permutations, but the kernel doesn't.
+ */
+ static void
+ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
+       rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_mday) & 0x3f,
+              RTC_ALARM_DATE);
+       rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_hour) & 0x3f,
+              RTC_ALARM_HOUR);
+       rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_min) & 0x7f,
+              RTC_ALARM_MIN);
+       rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_sec) & 0x7f,
+              RTC_ALARM_SEC);
+       rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
+       rtc_read(RTC_CMD1);     /* clear interrupts */
+       spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
+}
+
+ static int
+ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0) {
+               return -EINVAL;
+       }
+       pdata->alrm_mday = alrm->time.tm_mday;
+       pdata->alrm_hour = alrm->time.tm_hour;
+       pdata->alrm_min = alrm->time.tm_min;
+       pdata->alrm_sec = alrm->time.tm_sec;
+       if (alrm->enabled) {
+               pdata->irqen |= RTC_AF;
+       }
+       ds1511_rtc_update_alarm(pdata);
+       return 0;
+}
+
+ static int
+ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0) {
+               return -EINVAL;
+       }
+       alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+       alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+       alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+       alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+       alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+       return 0;
+}
+
+ static irqreturn_t
+ds1511_interrupt(int irq, void *dev_id)
+{
+       struct platform_device *pdev = dev_id;
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       unsigned long events = RTC_IRQF;
+
+       /*
+        * read and clear interrupt
+        */
+       if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) {
+               return IRQ_NONE;
+       }
+       if (rtc_read(RTC_ALARM_SEC) & 0x80) {
+               events |= RTC_UF;
+       } else {
+               events |= RTC_AF;
+       }
+       rtc_update_irq(pdata->rtc, 1, events);
+       return IRQ_HANDLED;
+}
+
+ static void
+ds1511_rtc_release(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq >= 0) {
+               pdata->irqen = 0;
+               ds1511_rtc_update_alarm(pdata);
+       }
+}
+
+ static int
+ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0) {
+               return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+       }
+       switch (cmd) {
+       case RTC_AIE_OFF:
+               pdata->irqen &= ~RTC_AF;
+               ds1511_rtc_update_alarm(pdata);
+               break;
+       case RTC_AIE_ON:
+               pdata->irqen |= RTC_AF;
+               ds1511_rtc_update_alarm(pdata);
+               break;
+       case RTC_UIE_OFF:
+               pdata->irqen &= ~RTC_UF;
+               ds1511_rtc_update_alarm(pdata);
+               break;
+       case RTC_UIE_ON:
+               pdata->irqen |= RTC_UF;
+               ds1511_rtc_update_alarm(pdata);
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static const struct rtc_class_ops ds1511_rtc_ops = {
+       .read_time      = ds1511_rtc_read_time,
+       .set_time       = ds1511_rtc_set_time,
+       .read_alarm     = ds1511_rtc_read_alarm,
+       .set_alarm      = ds1511_rtc_set_alarm,
+       .release        = ds1511_rtc_release,
+       .ioctl          = ds1511_rtc_ioctl,
+};
+
+ static ssize_t
+ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba,
+                               char *buf, loff_t pos, size_t size)
+{
+       ssize_t count;
+
+       /*
+        * if count is more than one, turn on "burst" mode
+        * turn it off when you're done
+        */
+       if (size > 1) {
+               rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
+       }
+       if (pos > DS1511_RAM_MAX) {
+               pos = DS1511_RAM_MAX;
+       }
+       if (size + pos > DS1511_RAM_MAX + 1) {
+               size = DS1511_RAM_MAX - pos + 1;
+       }
+       rtc_write(pos, DS1511_RAMADDR_LSB);
+       for (count = 0; size > 0; count++, size--) {
+               *buf++ = rtc_read(DS1511_RAMDATA);
+       }
+       if (count > 1) {
+               rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
+       }
+       return count;
+}
+
+ static ssize_t
+ds1511_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr,
+                               char *buf, loff_t pos, size_t size)
+{
+       ssize_t count;
+
+       /*
+        * if count is more than one, turn on "burst" mode
+        * turn it off when you're done
+        */
+       if (size > 1) {
+               rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
+       }
+       if (pos > DS1511_RAM_MAX) {
+               pos = DS1511_RAM_MAX;
+       }
+       if (size + pos > DS1511_RAM_MAX + 1) {
+               size = DS1511_RAM_MAX - pos + 1;
+       }
+       rtc_write(pos, DS1511_RAMADDR_LSB);
+       for (count = 0; size > 0; count++, size--) {
+               rtc_write(*buf++, DS1511_RAMDATA);
+       }
+       if (count > 1) {
+               rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
+       }
+       return count;
+}
+
+static struct bin_attribute ds1511_nvram_attr = {
+       .attr = {
+               .name = "nvram",
+               .mode = S_IRUGO | S_IWUGO,
+               .owner = THIS_MODULE,
+       },
+       .size = DS1511_RAM_MAX,
+       .read = ds1511_nvram_read,
+       .write = ds1511_nvram_write,
+};
+
+ static int __devinit
+ds1511_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       struct resource *res;
+       struct rtc_plat_data *pdata = NULL;
+       int ret = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               return -ENODEV;
+       }
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               return -ENOMEM;
+       }
+       pdata->irq = -1;
+       pdata->size = res->end - res->start + 1;
+       if (!request_mem_region(res->start, pdata->size, pdev->name)) {
+               ret = -EBUSY;
+               goto out;
+       }
+       pdata->baseaddr = res->start;
+       pdata->size = pdata->size;
+       ds1511_base = ioremap(pdata->baseaddr, pdata->size);
+       if (!ds1511_base) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       pdata->ioaddr = ds1511_base;
+       pdata->irq = platform_get_irq(pdev, 0);
+
+       /*
+        * turn on the clock and the crystal, etc.
+        */
+       rtc_write(0, RTC_CMD);
+       rtc_write(0, RTC_CMD1);
+       /*
+        * clear the wdog counter
+        */
+       rtc_write(0, DS1511_WD_MSEC);
+       rtc_write(0, DS1511_WD_SEC);
+       /*
+        * start the clock
+        */
+       rtc_enable_update();
+
+       /*
+        * check for a dying bat-tree
+        */
+       if (rtc_read(RTC_CMD1) & DS1511_BLF1) {
+               dev_warn(&pdev->dev, "voltage-low detected.\n");
+       }
+
+       /*
+        * if the platform has an interrupt in mind for this device,
+        * then by all means, set it
+        */
+       if (pdata->irq >= 0) {
+               rtc_read(RTC_CMD1);
+               if (request_irq(pdata->irq, ds1511_interrupt,
+                       IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {
+
+                       dev_warn(&pdev->dev, "interrupt not available.\n");
+                       pdata->irq = -1;
+               }
+       }
+
+       rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops,
+               THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto out;
+       }
+       pdata->rtc = rtc;
+       platform_set_drvdata(pdev, pdata);
+       ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+       if (ret) {
+               goto out;
+       }
+       return 0;
+ out:
+       if (pdata->rtc) {
+               rtc_device_unregister(pdata->rtc);
+       }
+       if (pdata->irq >= 0) {
+               free_irq(pdata->irq, pdev);
+       }
+       if (ds1511_base) {
+               iounmap(ds1511_base);
+               ds1511_base = NULL;
+       }
+       if (pdata->baseaddr) {
+               release_mem_region(pdata->baseaddr, pdata->size);
+       }
+
+       kfree(pdata);
+       return ret;
+}
+
+ static int __devexit
+ds1511_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+       rtc_device_unregister(pdata->rtc);
+       pdata->rtc = NULL;
+       if (pdata->irq >= 0) {
+               /*
+                * disable the alarm interrupt
+                */
+               rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD);
+               rtc_read(RTC_CMD1);
+               free_irq(pdata->irq, pdev);
+       }
+       iounmap(pdata->ioaddr);
+       ds1511_base = NULL;
+       release_mem_region(pdata->baseaddr, pdata->size);
+       kfree(pdata);
+       return 0;
+}
+
+static struct platform_driver ds1511_rtc_driver = {
+       .probe          = ds1511_rtc_probe,
+       .remove         = __devexit_p(ds1511_rtc_remove),
+       .driver         = {
+               .name   = "ds1511",
+               .owner  = THIS_MODULE,
+       },
+};
+
+ static int __init
+ds1511_rtc_init(void)
+{
+       return platform_driver_register(&ds1511_rtc_driver);
+}
+
+ static void __exit
+ds1511_rtc_exit(void)
+{
+       return platform_driver_unregister(&ds1511_rtc_driver);
+}
+
+module_init(ds1511_rtc_init);
+module_exit(ds1511_rtc_exit);
+
+MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
+MODULE_DESCRIPTION("Dallas DS1511 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
index c973ba94c422bc182c8b994dfd877dac967030bc..8b3997007506bbc44a0205e586acfd8f75e042ae 100644 (file)
@@ -163,27 +163,17 @@ static int pcf8583_read_mem(struct i2c_client *client, struct rtc_mem *mem)
 
 static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem)
 {
-       unsigned char addr[1];
-       struct i2c_msg msgs[2] = {
-               {
-                       .addr = client->addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = addr,
-               }, {
-                       .addr = client->addr,
-                       .flags = I2C_M_NOSTART,
-                       .len = mem->nr,
-                       .buf = mem->data,
-               }
-       };
+       unsigned char buf[9];
+       int ret;
 
-       if (mem->loc < 8)
+       if (mem->loc < 8 || mem->nr > 8)
                return -EINVAL;
 
-       addr[0] = mem->loc;
+       buf[0] = mem->loc;
+       memcpy(buf + 1, mem->data, mem->nr);
 
-       return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+       ret = i2c_master_send(client, buf, mem->nr + 1);
+       return ret == mem->nr + 1 ? 0 : -EIO;
 }
 
 static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
new file mode 100644 (file)
index 0000000..a64626a
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Driver for Epson RTC-9701JE
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Based on rtc-max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#define RSECCNT        0x00    /* Second Counter */
+#define RMINCNT        0x01    /* Minute Counter */
+#define RHRCNT 0x02    /* Hour Counter */
+#define RWKCNT 0x03    /* Week Counter */
+#define RDAYCNT        0x04    /* Day Counter */
+#define RMONCNT        0x05    /* Month Counter */
+#define RYRCNT 0x06    /* Year Counter */
+#define R100CNT        0x07    /* Y100 Counter */
+#define RMINAR 0x08    /* Minute Alarm */
+#define RHRAR  0x09    /* Hour Alarm */
+#define RWKAR  0x0a    /* Week/Day Alarm */
+#define RTIMCNT        0x0c    /* Interval Timer */
+#define REXT   0x0d    /* Extension Register */
+#define RFLAG  0x0e    /* RTC Flag Register */
+#define RCR    0x0f    /* RTC Control Register */
+
+static int write_reg(struct device *dev, int address, unsigned char data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[2];
+
+       buf[0] = address & 0x7f;
+       buf[1] = data;
+
+       return spi_write(spi, buf, ARRAY_SIZE(buf));
+}
+
+static int read_regs(struct device *dev, unsigned char *regs, int no_regs)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       u8 txbuf[1], rxbuf[1];
+       int k, ret;
+
+       ret = 0;
+
+       for (k = 0; ret == 0 && k < no_regs; k++) {
+               txbuf[0] = 0x80 | regs[k];
+               ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
+               regs[k] = rxbuf[0];
+       }
+
+       return ret;
+}
+
+static int r9701_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+       unsigned long time;
+       int ret;
+       unsigned char buf[] = { RSECCNT, RMINCNT, RHRCNT,
+                               RDAYCNT, RMONCNT, RYRCNT };
+
+       ret = read_regs(dev, buf, ARRAY_SIZE(buf));
+       if (ret)
+               return ret;
+
+       memset(dt, 0, sizeof(*dt));
+
+       dt->tm_sec = BCD2BIN(buf[0]); /* RSECCNT */
+       dt->tm_min = BCD2BIN(buf[1]); /* RMINCNT */
+       dt->tm_hour = BCD2BIN(buf[2]); /* RHRCNT */
+
+       dt->tm_mday = BCD2BIN(buf[3]); /* RDAYCNT */
+       dt->tm_mon = BCD2BIN(buf[4]) - 1; /* RMONCNT */
+       dt->tm_year = BCD2BIN(buf[5]) + 100; /* RYRCNT */
+
+       /* the rtc device may contain illegal values on power up
+        * according to the data sheet. make sure they are valid.
+        */
+
+       return rtc_valid_tm(dt);
+}
+
+static int r9701_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+       int ret, year;
+
+       year = dt->tm_year + 1900;
+       if (year >= 2100 || year < 2000)
+               return -EINVAL;
+
+       ret = write_reg(dev, RHRCNT, BIN2BCD(dt->tm_hour));
+       ret = ret ? ret : write_reg(dev, RMINCNT, BIN2BCD(dt->tm_min));
+       ret = ret ? ret : write_reg(dev, RSECCNT, BIN2BCD(dt->tm_sec));
+       ret = ret ? ret : write_reg(dev, RDAYCNT, BIN2BCD(dt->tm_mday));
+       ret = ret ? ret : write_reg(dev, RMONCNT, BIN2BCD(dt->tm_mon + 1));
+       ret = ret ? ret : write_reg(dev, RYRCNT, BIN2BCD(dt->tm_year - 100));
+       ret = ret ? ret : write_reg(dev, RWKCNT, 1 << dt->tm_wday);
+
+       return ret;
+}
+
+static const struct rtc_class_ops r9701_rtc_ops = {
+       .read_time      = r9701_get_datetime,
+       .set_time       = r9701_set_datetime,
+};
+
+static int __devinit r9701_probe(struct spi_device *spi)
+{
+       struct rtc_device *rtc;
+       unsigned char tmp;
+       int res;
+
+       rtc = rtc_device_register("r9701",
+                               &spi->dev, &r9701_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       dev_set_drvdata(&spi->dev, rtc);
+
+       tmp = R100CNT;
+       res = read_regs(&spi->dev, &tmp, 1);
+       if (res || tmp != 0x20) {
+               rtc_device_unregister(rtc);
+               return res;
+       }
+
+       return 0;
+}
+
+static int __devexit r9701_remove(struct spi_device *spi)
+{
+       struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
+
+       rtc_device_unregister(rtc);
+       return 0;
+}
+
+static struct spi_driver r9701_driver = {
+       .driver = {
+               .name   = "rtc-r9701",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = r9701_probe,
+       .remove = __devexit_p(r9701_remove),
+};
+
+static __init int r9701_init(void)
+{
+       return spi_register_driver(&r9701_driver);
+}
+module_init(r9701_init);
+
+static __exit void r9701_exit(void)
+{
+       spi_unregister_driver(&r9701_driver);
+}
+module_exit(r9701_exit);
+
+MODULE_DESCRIPTION("r9701 spi RTC driver");
+MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
+MODULE_LICENSE("GPL");
index e2041b4d0c8569ba93791a166520145e8cdaa9cd..86766f1f24965f07c7b2efce8a8d793e1e06445d 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/rtc.h>
 #include <linux/bcd.h>
 #include <linux/clk.h>
+#include <linux/log2.h>
 
 #include <asm/hardware.h>
 #include <asm/uaccess.h>
@@ -309,9 +310,7 @@ static int s3c_rtc_ioctl(struct device *dev,
                break;
 
        case RTC_IRQP_SET:
-               /* check for power of 2 */
-
-               if ((arg & (arg-1)) != 0 || arg < 1) {
+               if (!is_power_of_2(arg)) {
                        ret = -EINVAL;
                        goto exit;
                }
index 2eb38520f0c8cf267f57360ae16970623e316588..ee253cc45de1e1b1ed0df26ce7c3e73d243b30b2 100644 (file)
@@ -357,23 +357,15 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       if (pdev->dev.power.power_state.event != state.event) {
-               if (state.event == PM_EVENT_SUSPEND &&
-                   device_may_wakeup(&pdev->dev))
-                       enable_irq_wake(IRQ_RTCAlrm);
-
-               pdev->dev.power.power_state = state;
-       }
+       if (device_may_wakeup(&pdev->dev))
+               enable_irq_wake(IRQ_RTCAlrm);
        return 0;
 }
 
 static int sa1100_rtc_resume(struct platform_device *pdev)
 {
-       if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
-               if (device_may_wakeup(&pdev->dev))
-                       disable_irq_wake(IRQ_RTCAlrm);
-               pdev->dev.power.power_state = PMSG_ON;
-       }
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(IRQ_RTCAlrm);
        return 0;
 }
 #else
index 2ae0e8304d3aa83bd7f75cdd6052b4394ba31a8b..4d27ccc4fc069c174d5785ddfa7ad27aa55b35b4 100644 (file)
 
 /* device attributes */
 
+/*
+ * NOTE:  RTC times displayed in sysfs use the RTC's timezone.  That's
+ * ideally UTC.  However, PCs that also boot to MS-Windows normally use
+ * the local time and change to match daylight savings time.  That affects
+ * attributes including date, time, since_epoch, and wakealarm.
+ */
+
 static ssize_t
 rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
                char *buf)
@@ -113,13 +120,13 @@ rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
        unsigned long alarm;
        struct rtc_wkalrm alm;
 
-       /* Don't show disabled alarms; but the RTC could leave the
-        * alarm enabled after it's already triggered.  Alarms are
-        * conceptually one-shot, even though some common hardware
-        * (PCs) doesn't actually work that way.
+       /* Don't show disabled alarms.  For uniformity, RTC alarms are
+        * conceptually one-shot, even though some common RTCs (on PCs)
+        * don't actually work that way.
         *
-        * REVISIT maybe we should require RTC implementations to
-        * disable the RTC alarm after it triggers, for uniformity.
+        * NOTE: RTC implementations where the alarm doesn't match an
+        * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC
+        * alarms after they trigger, to ensure one-shot semantics.
         */
        retval = rtc_read_alarm(to_rtc_device(dev), &alm);
        if (retval == 0 && alm.enabled) {
index 19343f9675c31ba368c0f57d2ebfd66de06cf625..291ff6235fe2f0e234a5be1747fc57231a09d25c 100644 (file)
@@ -422,7 +422,7 @@ void s390_adjust_jiffies(void)
 /*
  * calibrate the delay loop
  */
-void __init calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
 {
        s390_adjust_jiffies();
        /* Print the good old Bogomips line .. */
index 23f27c9c989501e3d078f6a8532240b24bafe97f..5ac3a3e8dfafcb57020edf4855690f0961550703 100644 (file)
@@ -46,8 +46,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
     struct Scsi_Host *instance = cmd->device->host;
 
     /* don't allow DMA if the physical address is bad */
-    if (addr & A2091_XFER_MASK ||
-       (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    if (addr & A2091_XFER_MASK)
     {
        HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
            & ~0x1ff;
index d7255c8bf2811a87ba866145182972e9c44d4f57..3aeec963940bd7e386c0f2e0cc22939df31dd06f 100644 (file)
@@ -54,8 +54,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
      * end of a physical memory chunk, then allocate a bounce
      * buffer
      */
-    if (addr & A3000_XFER_MASK ||
-       (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    if (addr & A3000_XFER_MASK)
     {
        HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
            & ~0x1ff;
index 3bfd9296bbfaaa75dc314d9be939c05eb2688b82..93984c9dfe14fd695d23659665d596a549b461c7 100644 (file)
@@ -6472,7 +6472,7 @@ do_aic7xxx_isr(int irq, void *dev_id)
   unsigned long cpu_flags;
   struct aic7xxx_host *p;
   
-  p = (struct aic7xxx_host *)dev_id;
+  p = dev_id;
   if(!p)
     return IRQ_NONE;
   spin_lock_irqsave(p->host->host_lock, cpu_flags);
index 37741e9b5c3b297380f4203376041333b4958ad2..91f85226d08fc352ec7bbfe7cecaf585dae63cf7 100644 (file)
@@ -54,8 +54,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
     static int scsi_alloc_out_of_range = 0;
 
     /* use bounce buffer if the physical address is bad */
-    if (addr & HDATA(cmd->device->host)->dma_xfer_mask ||
-       (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    if (addr & HDATA(cmd->device->host)->dma_xfer_mask)
     {
        HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
            & ~0x1ff;
index d63f11e95abf7f428ec6fb903af3720e04c0a701..bd62131b97a1d431eef230ab0efd9ed487a7234f 100644 (file)
@@ -539,9 +539,9 @@ out:
                srp_iu_put(iue);
 }
 
-static irqreturn_t ibmvstgt_interrupt(int irq, void *data)
+static irqreturn_t ibmvstgt_interrupt(int dummy, void *data)
 {
-       struct srp_target *target = (struct srp_target *) data;
+       struct srp_target *target = data;
        struct vio_port *vport = target_to_port(target);
 
        vio_disable_interrupts(vport->dma_dev);
index 672c759ac24d7719c3371c191d572e25bd8c4d4f..77a62a1b12c3e52cf76df0c3f65f58e607d293b8 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/moduleparam.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/uio.h>
index 0d99120ab5a26bb3bc0540cb60f0139ed7d800a9..2b8a410e09595f87bffd264a44ce0a840cde599d 100644 (file)
@@ -84,9 +84,6 @@ extern wait_queue_head_t keypress_wait;
 
 struct tty_driver *serial_driver;
 
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL     1
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
index ddfb1eab736371a6676ccdd637d197865b32ea2f..84a054d7e9865aec10da1601a7e3f4deba7635c7 100644 (file)
@@ -465,20 +465,24 @@ config SERIAL_DZ
        bool "DECstation DZ serial driver"
        depends on MACH_DECSTATION && 32BIT
        select SERIAL_CORE
-       help
-         DZ11-family serial controllers for VAXstations, including the
-         DC7085, M7814, and M7819.
+       default y
+       ---help---
+         DZ11-family serial controllers for DECstations and VAXstations,
+         including the DC7085, M7814, and M7819.
 
 config SERIAL_DZ_CONSOLE
        bool "Support console on DECstation DZ serial driver"
        depends on SERIAL_DZ=y
        select SERIAL_CORE_CONSOLE
-       help
+       default y
+       ---help---
          If you say Y here, it will be possible to use a serial port as the
          system console (the system console is the device which receives all
          kernel messages and warnings and which allows logins in single user
-         mode).  Note that the firmware uses ttyS0 as the serial console on
-         the Maxine and ttyS2 on the others.
+         mode).
+
+         Note that the firmware uses ttyS3 as the serial console on
+         DECstations that use this driver.
 
          If unsure, say Y.
 
@@ -877,15 +881,15 @@ config SERIAL_SUNHV
          systems.  Say Y if you want to be able to use this device.
 
 config SERIAL_IP22_ZILOG
-       tristate "IP22 Zilog8530 serial support"
-       depends on SGI_IP22
+       tristate "SGI Zilog8530 serial support"
+       depends on SGI_HAS_ZILOG
        select SERIAL_CORE
        help
-         This driver supports the Zilog8530 serial ports found on SGI IP22
+         This driver supports the Zilog8530 serial ports found on SGI
          systems.  Say Y or M if you want to be able to these serial ports.
 
 config SERIAL_IP22_ZILOG_CONSOLE
-       bool "Console on IP22 Zilog8530 serial port"
+       bool "Console on SGI Zilog8530 serial port"
        depends on SERIAL_IP22_ZILOG=y
        select SERIAL_CORE_CONSOLE
 
@@ -1318,4 +1322,19 @@ config SERIAL_QE
          This driver supports the QE serial ports on Freescale embedded
          PowerPC that contain a QUICC Engine.
 
+config SERIAL_SC26XX
+       tristate "SC2681/SC2692 serial port support"
+       depends on SNI_RM
+       select SERIAL_CORE
+       help
+         This is a driver for the onboard serial ports of
+         older RM400 machines.
+
+config SERIAL_SC26XX_CONSOLE
+       bool "Console on SC2681/SC2692 serial port"
+       depends on SERIAL_SC26XX
+       select SERIAL_CORE_CONSOLE
+       help
+         Support for Console on SC2681/SC2692 serial ports.
+
 endmenu
index 2dd41b4cc8dbf1cc930b852a8d4c0fea67d94db0..640cfe44a56dd309cacc16efa2c86378af5048c2 100644 (file)
@@ -55,6 +55,7 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
 obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
 obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
 obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
 obj-$(CONFIG_SERIAL_JSM) += jsm/
 obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
 obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
index b5e4478de0e3b31f3ef6a0adbfce536d5986d6c8..236af9d3385123897985a84ff215cf395b3a2ff0 100644 (file)
@@ -380,7 +380,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
 static irqreturn_t cpm_uart_int(int irq, void *data)
 {
        u8 events;
-       struct uart_port *port = (struct uart_port *)data;
+       struct uart_port *port = data;
        struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
        smc_t __iomem *smcp = pinfo->smcp;
        scc_t __iomem *sccp = pinfo->sccp;
index a4e23cf47906960ba53396984d6e0d3e531619b3..383c4e660cd5c25da1ab86db8a408dcc7f9badd2 100644 (file)
@@ -68,11 +68,6 @@ static char *serial_version = "$Revision: 1.25 $";
 
 struct tty_driver *serial_driver;
 
-/* serial subtype definitions */
-#ifndef SERIAL_TYPE_NORMAL
-#define SERIAL_TYPE_NORMAL     1
-#endif
-
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
index d31721f2744d69db038b69b7c0f2a9e143cc362d..116211fcd36fc196ff12de4aeb36ee8e6194031f 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Email: olivier.lebaillif@ifrsys.com
  *
- * Copyright (C) 2004, 2006  Maciej W. Rozycki
+ * Copyright (C) 2004, 2006, 2007  Maciej W. Rozycki
  *
  * [31-AUG-98] triemer
  * Changed IRQ to use Harald's dec internals interrupts.h
 #define SUPPORT_SYSRQ
 #endif
 
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/console.h>
 #include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
+#include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/console.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
 #include <linux/sysrq.h>
 #include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
 
+#include <asm/atomic.h>
 #include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
 #include <asm/dec/interrupts.h>
 #include <asm/dec/kn01.h>
 #include <asm/dec/kn02.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/prom.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
+#include <asm/dec/system.h>
 
 #include "dz.h"
 
-static char *dz_name = "DECstation DZ serial driver version ";
-static char *dz_version = "1.03";
+
+MODULE_DESCRIPTION("DECstation DZ serial driver");
+MODULE_LICENSE("GPL");
+
+
+static char dz_name[] __initdata = "DECstation DZ serial driver version ";
+static char dz_version[] __initdata = "1.04";
 
 struct dz_port {
+       struct dz_mux           *mux;
        struct uart_port        port;
        unsigned int            cflag;
 };
 
-static struct dz_port dz_ports[DZ_NB_PORT];
+struct dz_mux {
+       struct dz_port          dport[DZ_NB_PORT];
+       atomic_t                map_guard;
+       atomic_t                irq_guard;
+       int                     initialised;
+};
+
+static struct dz_mux dz_mux;
+
+static inline struct dz_port *to_dport(struct uart_port *uport)
+{
+       return container_of(uport, struct dz_port, port);
+}
 
 /*
  * ------------------------------------------------------------
@@ -74,21 +99,18 @@ static struct dz_port dz_ports[DZ_NB_PORT];
  * ------------------------------------------------------------
  */
 
-static inline unsigned short dz_in(struct dz_port *dport, unsigned offset)
+static u16 dz_in(struct dz_port *dport, unsigned offset)
 {
-       volatile unsigned short *addr =
-               (volatile unsigned short *) (dport->port.membase + offset);
+       void __iomem *addr = dport->port.membase + offset;
 
-       return *addr;
+       return readw(addr);
 }
 
-static inline void dz_out(struct dz_port *dport, unsigned offset,
-                          unsigned short value)
+static void dz_out(struct dz_port *dport, unsigned offset, u16 value)
 {
-       volatile unsigned short *addr =
-               (volatile unsigned short *) (dport->port.membase + offset);
+       void __iomem *addr = dport->port.membase + offset;
 
-       *addr = value;
+       writew(value, addr);
 }
 
 /*
@@ -103,42 +125,33 @@ static inline void dz_out(struct dz_port *dport, unsigned offset,
 
 static void dz_stop_tx(struct uart_port *uport)
 {
-       struct dz_port *dport = (struct dz_port *)uport;
-       unsigned short tmp, mask = 1 << dport->port.line;
-       unsigned long flags;
+       struct dz_port *dport = to_dport(uport);
+       u16 tmp, mask = 1 << dport->port.line;
 
-       spin_lock_irqsave(&dport->port.lock, flags);
        tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
        tmp &= ~mask;                   /* clear the TX flag */
        dz_out(dport, DZ_TCR, tmp);
-       spin_unlock_irqrestore(&dport->port.lock, flags);
 }
 
 static void dz_start_tx(struct uart_port *uport)
 {
-       struct dz_port *dport = (struct dz_port *)uport;
-       unsigned short tmp, mask = 1 << dport->port.line;
-       unsigned long flags;
+       struct dz_port *dport = to_dport(uport);
+       u16 tmp, mask = 1 << dport->port.line;
 
-       spin_lock_irqsave(&dport->port.lock, flags);
        tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
        tmp |= mask;                    /* set the TX flag */
        dz_out(dport, DZ_TCR, tmp);
-       spin_unlock_irqrestore(&dport->port.lock, flags);
 }
 
 static void dz_stop_rx(struct uart_port *uport)
 {
-       struct dz_port *dport = (struct dz_port *)uport;
-       unsigned long flags;
+       struct dz_port *dport = to_dport(uport);
 
-       spin_lock_irqsave(&dport->port.lock, flags);
-       dport->cflag &= ~DZ_CREAD;
-       dz_out(dport, DZ_LPR, dport->cflag | dport->port.line);
-       spin_unlock_irqrestore(&dport->port.lock, flags);
+       dport->cflag &= ~DZ_RXENAB;
+       dz_out(dport, DZ_LPR, dport->cflag);
 }
 
-static void dz_enable_ms(struct uart_port *port)
+static void dz_enable_ms(struct uart_port *uport)
 {
        /* nothing to do */
 }
@@ -170,73 +183,73 @@ static void dz_enable_ms(struct uart_port *port)
  * This routine deals with inputs from any lines.
  * ------------------------------------------------------------
  */
-static inline void dz_receive_chars(struct dz_port *dport_in)
+static inline void dz_receive_chars(struct dz_mux *mux)
 {
-       struct dz_port *dport;
+       struct uart_port *uport;
+       struct dz_port *dport = &mux->dport[0];
        struct tty_struct *tty = NULL;
        struct uart_icount *icount;
        int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 };
-       unsigned short status;
        unsigned char ch, flag;
+       u16 status;
        int i;
 
-       while ((status = dz_in(dport_in, DZ_RBUF)) & DZ_DVAL) {
-               dport = &dz_ports[LINE(status)];
-               tty = dport->port.info->tty;    /* point to the proper dev */
+       while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) {
+               dport = &mux->dport[LINE(status)];
+               uport = &dport->port;
+               tty = uport->info->tty;         /* point to the proper dev */
 
                ch = UCHAR(status);             /* grab the char */
+               flag = TTY_NORMAL;
 
-               icount = &dport->port.icount;
+               icount = &uport->icount;
                icount->rx++;
 
-               flag = TTY_NORMAL;
-               if (status & DZ_FERR) {         /* frame error */
+               if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) {
+
                        /*
-                        * There is no separate BREAK status bit, so
-                        * treat framing errors as BREAKs for Magic SysRq
-                        * and SAK; normally, otherwise.
+                        * There is no separate BREAK status bit, so treat
+                        * null characters with framing errors as BREAKs;
+                        * normally, otherwise.  For this move the Framing
+                        * Error bit to a simulated BREAK bit.
                         */
-                       if (uart_handle_break(&dport->port))
-                               continue;
-                       if (dport->port.flags & UPF_SAK)
+                       if (!ch) {
+                               status |= (status & DZ_FERR) >>
+                                         (ffs(DZ_FERR) - ffs(DZ_BREAK));
+                               status &= ~DZ_FERR;
+                       }
+
+                       /* Handle SysRq/SAK & keep track of the statistics. */
+                       if (status & DZ_BREAK) {
+                               icount->brk++;
+                               if (uart_handle_break(uport))
+                                       continue;
+                       } else if (status & DZ_FERR)
+                               icount->frame++;
+                       else if (status & DZ_PERR)
+                               icount->parity++;
+                       if (status & DZ_OERR)
+                               icount->overrun++;
+
+                       status &= uport->read_status_mask;
+                       if (status & DZ_BREAK)
                                flag = TTY_BREAK;
-                       else
+                       else if (status & DZ_FERR)
                                flag = TTY_FRAME;
-               } else if (status & DZ_OERR)    /* overrun error */
-                       flag = TTY_OVERRUN;
-               else if (status & DZ_PERR)      /* parity error */
-                       flag = TTY_PARITY;
-
-               /* keep track of the statistics */
-               switch (flag) {
-               case TTY_FRAME:
-                       icount->frame++;
-                       break;
-               case TTY_PARITY:
-                       icount->parity++;
-                       break;
-               case TTY_OVERRUN:
-                       icount->overrun++;
-                       break;
-               case TTY_BREAK:
-                       icount->brk++;
-                       break;
-               default:
-                       break;
+                       else if (status & DZ_PERR)
+                               flag = TTY_PARITY;
+
                }
 
-               if (uart_handle_sysrq_char(&dport->port, ch))
+               if (uart_handle_sysrq_char(uport, ch))
                        continue;
 
-               if ((status & dport->port.ignore_status_mask) == 0) {
-                       uart_insert_char(&dport->port,
-                                        status, DZ_OERR, ch, flag);
-                       lines_rx[LINE(status)] = 1;
-               }
+               uart_insert_char(uport, status, DZ_OERR, ch, flag);
+               lines_rx[LINE(status)] = 1;
        }
        for (i = 0; i < DZ_NB_PORT; i++)
                if (lines_rx[i])
-                       tty_flip_buffer_push(dz_ports[i].port.info->tty);
+                       tty_flip_buffer_push(mux->dport[i].port.info->tty);
 }
 
 /*
@@ -246,15 +259,15 @@ static inline void dz_receive_chars(struct dz_port *dport_in)
  * This routine deals with outputs to any lines.
  * ------------------------------------------------------------
  */
-static inline void dz_transmit_chars(struct dz_port *dport_in)
+static inline void dz_transmit_chars(struct dz_mux *mux)
 {
-       struct dz_port *dport;
+       struct dz_port *dport = &mux->dport[0];
        struct circ_buf *xmit;
-       unsigned short status;
        unsigned char tmp;
+       u16 status;
 
-       status = dz_in(dport_in, DZ_CSR);
-       dport = &dz_ports[LINE(status)];
+       status = dz_in(dport, DZ_CSR);
+       dport = &mux->dport[LINE(status)];
        xmit = &dport->port.info->xmit;
 
        if (dport->port.x_char) {               /* XON/XOFF chars */
@@ -265,7 +278,9 @@ static inline void dz_transmit_chars(struct dz_port *dport_in)
        }
        /* If nothing to do or stopped or hardware stopped. */
        if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
+               spin_lock(&dport->port.lock);
                dz_stop_tx(&dport->port);
+               spin_unlock(&dport->port.lock);
                return;
        }
 
@@ -282,8 +297,11 @@ static inline void dz_transmit_chars(struct dz_port *dport_in)
                uart_write_wakeup(&dport->port);
 
        /* Are we are done. */
-       if (uart_circ_empty(xmit))
+       if (uart_circ_empty(xmit)) {
+               spin_lock(&dport->port.lock);
                dz_stop_tx(&dport->port);
+               spin_unlock(&dport->port.lock);
+       }
 }
 
 /*
@@ -301,7 +319,7 @@ static inline void check_modem_status(struct dz_port *dport)
         * 1. No status change interrupt; use a timer.
         * 2. Handle the 3100/5000 as appropriate. --macro
         */
-       unsigned short status;
+       u16 status;
 
        /* If not the modem line just return.  */
        if (dport->port.line != DZ_MODEM)
@@ -322,19 +340,20 @@ static inline void check_modem_status(struct dz_port *dport)
  * It deals with the multiple ports.
  * ------------------------------------------------------------
  */
-static irqreturn_t dz_interrupt(int irq, void *dev)
+static irqreturn_t dz_interrupt(int irq, void *dev_id)
 {
-       struct dz_port *dport = (struct dz_port *)dev;
-       unsigned short status;
+       struct dz_mux *mux = dev_id;
+       struct dz_port *dport = &mux->dport[0];
+       u16 status;
 
        /* get the reason why we just got an irq */
        status = dz_in(dport, DZ_CSR);
 
        if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE))
-               dz_receive_chars(dport);
+               dz_receive_chars(mux);
 
        if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE))
-               dz_transmit_chars(dport);
+               dz_transmit_chars(mux);
 
        return IRQ_HANDLED;
 }
@@ -350,7 +369,7 @@ static unsigned int dz_get_mctrl(struct uart_port *uport)
        /*
         * FIXME: Handle the 3100/5000 as appropriate. --macro
         */
-       struct dz_port *dport = (struct dz_port *)uport;
+       struct dz_port *dport = to_dport(uport);
        unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
 
        if (dport->port.line == DZ_MODEM) {
@@ -366,8 +385,8 @@ static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
        /*
         * FIXME: Handle the 3100/5000 as appropriate. --macro
         */
-       struct dz_port *dport = (struct dz_port *)uport;
-       unsigned short tmp;
+       struct dz_port *dport = to_dport(uport);
+       u16 tmp;
 
        if (dport->port.line == DZ_MODEM) {
                tmp = dz_in(dport, DZ_TCR);
@@ -388,15 +407,30 @@ static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
  */
 static int dz_startup(struct uart_port *uport)
 {
-       struct dz_port *dport = (struct dz_port *)uport;
+       struct dz_port *dport = to_dport(uport);
+       struct dz_mux *mux = dport->mux;
        unsigned long flags;
-       unsigned short tmp;
+       int irq_guard;
+       int ret;
+       u16 tmp;
+
+       irq_guard = atomic_add_return(1, &mux->irq_guard);
+       if (irq_guard != 1)
+               return 0;
+
+       ret = request_irq(dport->port.irq, dz_interrupt,
+                         IRQF_SHARED, "dz", mux);
+       if (ret) {
+               atomic_add(-1, &mux->irq_guard);
+               printk(KERN_ERR "dz: Cannot get IRQ %d!\n", dport->port.irq);
+               return ret;
+       }
 
        spin_lock_irqsave(&dport->port.lock, flags);
 
-       /* enable the interrupt and the scanning */
+       /* Enable interrupts.  */
        tmp = dz_in(dport, DZ_CSR);
-       tmp |= DZ_RIE | DZ_TIE | DZ_MSE;
+       tmp |= DZ_RIE | DZ_TIE;
        dz_out(dport, DZ_CSR, tmp);
 
        spin_unlock_irqrestore(&dport->port.lock, flags);
@@ -414,7 +448,25 @@ static int dz_startup(struct uart_port *uport)
  */
 static void dz_shutdown(struct uart_port *uport)
 {
-       dz_stop_tx(uport);
+       struct dz_port *dport = to_dport(uport);
+       struct dz_mux *mux = dport->mux;
+       unsigned long flags;
+       int irq_guard;
+       u16 tmp;
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+       dz_stop_tx(&dport->port);
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+
+       irq_guard = atomic_add_return(-1, &mux->irq_guard);
+       if (!irq_guard) {
+               /* Disable interrupts.  */
+               tmp = dz_in(dport, DZ_CSR);
+               tmp &= ~(DZ_RIE | DZ_TIE);
+               dz_out(dport, DZ_CSR, tmp);
+
+               free_irq(dport->port.irq, mux);
+       }
 }
 
 /*
@@ -431,7 +483,7 @@ static void dz_shutdown(struct uart_port *uport)
  */
 static unsigned int dz_tx_empty(struct uart_port *uport)
 {
-       struct dz_port *dport = (struct dz_port *)uport;
+       struct dz_port *dport = to_dport(uport);
        unsigned short tmp, mask = 1 << dport->port.line;
 
        tmp = dz_in(dport, DZ_TCR);
@@ -446,7 +498,7 @@ static void dz_break_ctl(struct uart_port *uport, int break_state)
         * FIXME: Can't access BREAK bits in TDR easily;
         * reuse the code for polled TX. --macro
         */
-       struct dz_port *dport = (struct dz_port *)uport;
+       struct dz_port *dport = to_dport(uport);
        unsigned long flags;
        unsigned short tmp, mask = 1 << dport->port.line;
 
@@ -460,12 +512,69 @@ static void dz_break_ctl(struct uart_port *uport, int break_state)
        spin_unlock_irqrestore(&uport->lock, flags);
 }
 
+static int dz_encode_baud_rate(unsigned int baud)
+{
+       switch (baud) {
+       case 50:
+               return DZ_B50;
+       case 75:
+               return DZ_B75;
+       case 110:
+               return DZ_B110;
+       case 134:
+               return DZ_B134;
+       case 150:
+               return DZ_B150;
+       case 300:
+               return DZ_B300;
+       case 600:
+               return DZ_B600;
+       case 1200:
+               return DZ_B1200;
+       case 1800:
+               return DZ_B1800;
+       case 2000:
+               return DZ_B2000;
+       case 2400:
+               return DZ_B2400;
+       case 3600:
+               return DZ_B3600;
+       case 4800:
+               return DZ_B4800;
+       case 7200:
+               return DZ_B7200;
+       case 9600:
+               return DZ_B9600;
+       default:
+               return -1;
+       }
+}
+
+
+static void dz_reset(struct dz_port *dport)
+{
+       struct dz_mux *mux = dport->mux;
+
+       if (mux->initialised)
+               return;
+
+       dz_out(dport, DZ_CSR, DZ_CLR);
+       while (dz_in(dport, DZ_CSR) & DZ_CLR);
+       iob();
+
+       /* Enable scanning.  */
+       dz_out(dport, DZ_CSR, DZ_MSE);
+
+       mux->initialised = 1;
+}
+
 static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
                           struct ktermios *old_termios)
 {
-       struct dz_port *dport = (struct dz_port *)uport;
+       struct dz_port *dport = to_dport(uport);
        unsigned long flags;
        unsigned int cflag, baud;
+       int bflag;
 
        cflag = dport->port.line;
 
@@ -492,105 +601,127 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
                cflag |= DZ_PARODD;
 
        baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600);
-       switch (baud) {
-       case 50:
-               cflag |= DZ_B50;
-               break;
-       case 75:
-               cflag |= DZ_B75;
-               break;
-       case 110:
-               cflag |= DZ_B110;
-               break;
-       case 134:
-               cflag |= DZ_B134;
-               break;
-       case 150:
-               cflag |= DZ_B150;
-               break;
-       case 300:
-               cflag |= DZ_B300;
-               break;
-       case 600:
-               cflag |= DZ_B600;
-               break;
-       case 1200:
-               cflag |= DZ_B1200;
-               break;
-       case 1800:
-               cflag |= DZ_B1800;
-               break;
-       case 2000:
-               cflag |= DZ_B2000;
-               break;
-       case 2400:
-               cflag |= DZ_B2400;
-               break;
-       case 3600:
-               cflag |= DZ_B3600;
-               break;
-       case 4800:
-               cflag |= DZ_B4800;
-               break;
-       case 7200:
-               cflag |= DZ_B7200;
-               break;
-       case 9600:
-       default:
-               cflag |= DZ_B9600;
+       bflag = dz_encode_baud_rate(baud);
+       if (bflag < 0)  {                       /* Try to keep unchanged.  */
+               baud = uart_get_baud_rate(uport, old_termios, NULL, 50, 9600);
+               bflag = dz_encode_baud_rate(baud);
+               if (bflag < 0)  {               /* Resort to 9600.  */
+                       baud = 9600;
+                       bflag = DZ_B9600;
+               }
+               tty_termios_encode_baud_rate(termios, baud, baud);
        }
+       cflag |= bflag;
 
        if (termios->c_cflag & CREAD)
                cflag |= DZ_RXENAB;
 
        spin_lock_irqsave(&dport->port.lock, flags);
 
-       dz_out(dport, DZ_LPR, cflag | dport->port.line);
+       uart_update_timeout(uport, termios->c_cflag, baud);
+
+       dz_out(dport, DZ_LPR, cflag);
        dport->cflag = cflag;
 
        /* setup accept flag */
        dport->port.read_status_mask = DZ_OERR;
        if (termios->c_iflag & INPCK)
                dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               dport->port.read_status_mask |= DZ_BREAK;
 
        /* characters to ignore */
        uport->ignore_status_mask = 0;
+       if ((termios->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
+               dport->port.ignore_status_mask |= DZ_OERR;
        if (termios->c_iflag & IGNPAR)
                dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;
+       if (termios->c_iflag & IGNBRK)
+               dport->port.ignore_status_mask |= DZ_BREAK;
 
        spin_unlock_irqrestore(&dport->port.lock, flags);
 }
 
-static const char *dz_type(struct uart_port *port)
+static const char *dz_type(struct uart_port *uport)
 {
        return "DZ";
 }
 
-static void dz_release_port(struct uart_port *port)
+static void dz_release_port(struct uart_port *uport)
 {
-       /* nothing to do */
+       struct dz_mux *mux = to_dport(uport)->mux;
+       int map_guard;
+
+       iounmap(uport->membase);
+       uport->membase = NULL;
+
+       map_guard = atomic_add_return(-1, &mux->map_guard);
+       if (!map_guard)
+               release_mem_region(uport->mapbase, dec_kn_slot_size);
 }
 
-static int dz_request_port(struct uart_port *port)
+static int dz_map_port(struct uart_port *uport)
 {
+       if (!uport->membase)
+               uport->membase = ioremap_nocache(uport->mapbase,
+                                                dec_kn_slot_size);
+       if (!uport->membase) {
+               printk(KERN_ERR "dz: Cannot map MMIO\n");
+               return -ENOMEM;
+       }
        return 0;
 }
 
-static void dz_config_port(struct uart_port *port, int flags)
+static int dz_request_port(struct uart_port *uport)
 {
-       if (flags & UART_CONFIG_TYPE)
-               port->type = PORT_DZ;
+       struct dz_mux *mux = to_dport(uport)->mux;
+       int map_guard;
+       int ret;
+
+       map_guard = atomic_add_return(1, &mux->map_guard);
+       if (map_guard == 1) {
+               if (!request_mem_region(uport->mapbase, dec_kn_slot_size,
+                                       "dz")) {
+                       atomic_add(-1, &mux->map_guard);
+                       printk(KERN_ERR
+                              "dz: Unable to reserve MMIO resource\n");
+                       return -EBUSY;
+               }
+       }
+       ret = dz_map_port(uport);
+       if (ret) {
+               map_guard = atomic_add_return(-1, &mux->map_guard);
+               if (!map_guard)
+                       release_mem_region(uport->mapbase, dec_kn_slot_size);
+               return ret;
+       }
+       return 0;
+}
+
+static void dz_config_port(struct uart_port *uport, int flags)
+{
+       struct dz_port *dport = to_dport(uport);
+
+       if (flags & UART_CONFIG_TYPE) {
+               if (dz_request_port(uport))
+                       return;
+
+               uport->type = PORT_DZ;
+
+               dz_reset(dport);
+       }
 }
 
 /*
- * verify the new serial_struct (for TIOCSSERIAL).
+ * Verify the new serial_struct (for TIOCSSERIAL).
  */
-static int dz_verify_port(struct uart_port *port, struct serial_struct *ser)
+static int dz_verify_port(struct uart_port *uport, struct serial_struct *ser)
 {
        int ret = 0;
+
        if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ)
                ret = -EINVAL;
-       if (ser->irq != port->irq)
+       if (ser->irq != uport->irq)
                ret = -EINVAL;
        return ret;
 }
@@ -617,40 +748,32 @@ static struct uart_ops dz_ops = {
 static void __init dz_init_ports(void)
 {
        static int first = 1;
-       struct dz_port *dport;
        unsigned long base;
-       int i;
+       int line;
 
        if (!first)
                return;
        first = 0;
 
-       if (mips_machtype == MACH_DS23100 ||
-           mips_machtype == MACH_DS5100)
-               base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_DZ11);
+       if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100)
+               base = dec_kn_slot_base + KN01_DZ11;
        else
-               base = CKSEG1ADDR(KN02_SLOT_BASE + KN02_DZ11);
-
-       for (i = 0, dport = dz_ports; i < DZ_NB_PORT; i++, dport++) {
-               spin_lock_init(&dport->port.lock);
-               dport->port.membase     = (char *) base;
-               dport->port.iotype      = UPIO_MEM;
-               dport->port.irq         = dec_interrupt[DEC_IRQ_DZ11];
-               dport->port.line        = i;
-               dport->port.fifosize    = 1;
-               dport->port.ops         = &dz_ops;
-               dport->port.flags       = UPF_BOOT_AUTOCONF;
-       }
-}
+               base = dec_kn_slot_base + KN02_DZ11;
 
-static void dz_reset(struct dz_port *dport)
-{
-       dz_out(dport, DZ_CSR, DZ_CLR);
-       while (dz_in(dport, DZ_CSR) & DZ_CLR);
-       iob();
+       for (line = 0; line < DZ_NB_PORT; line++) {
+               struct dz_port *dport = &dz_mux.dport[line];
+               struct uart_port *uport = &dport->port;
 
-       /* enable scanning */
-       dz_out(dport, DZ_CSR, DZ_MSE);
+               dport->mux      = &dz_mux;
+
+               uport->irq      = dec_interrupt[DEC_IRQ_DZ11];
+               uport->fifosize = 1;
+               uport->iotype   = UPIO_MEM;
+               uport->flags    = UPF_BOOT_AUTOCONF;
+               uport->ops      = &dz_ops;
+               uport->line     = line;
+               uport->mapbase  = base;
+       }
 }
 
 #ifdef CONFIG_SERIAL_DZ_CONSOLE
@@ -670,7 +793,7 @@ static void dz_reset(struct dz_port *dport)
  */
 static void dz_console_putchar(struct uart_port *uport, int ch)
 {
-       struct dz_port *dport = (struct dz_port *)uport;
+       struct dz_port *dport = to_dport(uport);
        unsigned long flags;
        unsigned short csr, tcr, trdy, mask;
        int loops = 10000;
@@ -685,7 +808,7 @@ static void dz_console_putchar(struct uart_port *uport, int ch)
        iob();
        spin_unlock_irqrestore(&dport->port.lock, flags);
 
-       while (loops--) {
+       do {
                trdy = dz_in(dport, DZ_CSR);
                if (!(trdy & DZ_TRDY))
                        continue;
@@ -696,7 +819,7 @@ static void dz_console_putchar(struct uart_port *uport, int ch)
                dz_out(dport, DZ_TCR, mask);
                iob();
                udelay(2);
-       }
+       } while (loops--);
 
        if (loops)                              /* Cannot send otherwise. */
                dz_out(dport, DZ_TDR, ch);
@@ -717,7 +840,7 @@ static void dz_console_print(struct console *co,
                             const char *str,
                             unsigned int count)
 {
-       struct dz_port *dport = &dz_ports[co->index];
+       struct dz_port *dport = &dz_mux.dport[co->index];
 #ifdef DEBUG_DZ
        prom_printf((char *) str);
 #endif
@@ -726,22 +849,28 @@ static void dz_console_print(struct console *co,
 
 static int __init dz_console_setup(struct console *co, char *options)
 {
-       struct dz_port *dport = &dz_ports[co->index];
+       struct dz_port *dport = &dz_mux.dport[co->index];
+       struct uart_port *uport = &dport->port;
        int baud = 9600;
        int bits = 8;
        int parity = 'n';
        int flow = 'n';
+       int ret;
 
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       ret = dz_map_port(uport);
+       if (ret)
+               return ret;
 
        dz_reset(dport);
 
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
        return uart_set_options(&dport->port, co, baud, parity, bits, flow);
 }
 
 static struct uart_driver dz_reg;
-static struct console dz_sercons = {
+static struct console dz_console = {
        .name   = "ttyS",
        .write  = dz_console_print,
        .device = uart_console_device,
@@ -755,7 +884,7 @@ static int __init dz_serial_console_init(void)
 {
        if (!IOASIC) {
                dz_init_ports();
-               register_console(&dz_sercons);
+               register_console(&dz_console);
                return 0;
        } else
                return -ENXIO;
@@ -763,7 +892,7 @@ static int __init dz_serial_console_init(void)
 
 console_initcall(dz_serial_console_init);
 
-#define SERIAL_DZ_CONSOLE      &dz_sercons
+#define SERIAL_DZ_CONSOLE      &dz_console
 #else
 #define SERIAL_DZ_CONSOLE      NULL
 #endif /* CONFIG_SERIAL_DZ_CONSOLE */
@@ -789,26 +918,14 @@ static int __init dz_init(void)
 
        dz_init_ports();
 
-#ifndef CONFIG_SERIAL_DZ_CONSOLE
-       /* reset the chip */
-       dz_reset(&dz_ports[0]);
-#endif
-
-       if (request_irq(dz_ports[0].port.irq, dz_interrupt,
-                       IRQF_DISABLED, "DZ", &dz_ports[0]))
-               panic("Unable to register DZ interrupt");
-
        ret = uart_register_driver(&dz_reg);
-       if (ret != 0)
+       if (ret)
                return ret;
 
        for (i = 0; i < DZ_NB_PORT; i++)
-               uart_add_one_port(&dz_reg, &dz_ports[i].port);
+               uart_add_one_port(&dz_reg, &dz_mux.dport[i].port);
 
-       return ret;
+       return 0;
 }
 
 module_init(dz_init);
-
-MODULE_DESCRIPTION("DECstation DZ serial driver");
-MODULE_LICENSE("GPL");
index 9674d4e4987251ac72e1e7c45e88e0e70228b638..faf169ed27b36e282206679dc8d7c8bb78e99355 100644 (file)
@@ -33,6 +33,8 @@
 #define DZ_FERR        0x2000                 /* Frame error indicator */
 #define DZ_PERR        0x1000                 /* Parity error indicator */
 
+#define DZ_BREAK       0x0800                 /* BREAK event software flag */
+
 #define LINE(x) ((x & DZ_LINE_MASK) >> 8)     /* Get the line number
                                                  from the input buffer */
 #define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK))
 #define DZ_B7200         0x0D00
 #define DZ_B9600         0x0E00
 
-#define DZ_CREAD         0x1000               /* Enable receiver */
-#define DZ_RXENAB        0x1000               /* enable receive char */
+#define DZ_RXENAB        0x1000               /* Receiver Enable */
+
 /*
  * Addresses for the DZ registers
  */
 #define DZ_XMIT_SIZE   4096                 /* buffer size */
 #define DZ_WAKEUP_CHARS   DZ_XMIT_SIZE/4
 
-#ifdef MODULE
-int init_module (void)
-void cleanup_module (void)
-#endif
-
 #endif /* DZ_SERIAL_H */
index dc1967176fe228811b77a27fb2fcb82c41c8274c..56af1f566a4cd1b0ebfc7d78f71646ca267face9 100644 (file)
@@ -308,7 +308,7 @@ static void imx_start_tx(struct uart_port *port)
 
 static irqreturn_t imx_rtsint(int irq, void *dev_id)
 {
-       struct imx_port *sport = (struct imx_port *)dev_id;
+       struct imx_port *sport = dev_id;
        unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
        unsigned long flags;
 
@@ -324,7 +324,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id)
 
 static irqreturn_t imx_txint(int irq, void *dev_id)
 {
-       struct imx_port *sport = (struct imx_port *)dev_id;
+       struct imx_port *sport = dev_id;
        struct circ_buf *xmit = &sport->port.info->xmit;
        unsigned long flags;
 
diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c
new file mode 100644 (file)
index 0000000..a350b6d
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
+ *
+ * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define SC26XX_MAJOR         204
+#define SC26XX_MINOR_START   205
+#define SC26XX_NR            2
+
+struct uart_sc26xx_port {
+       struct uart_port      port[2];
+       u8     dsr_mask[2];
+       u8     cts_mask[2];
+       u8     dcd_mask[2];
+       u8     ri_mask[2];
+       u8     dtr_mask[2];
+       u8     rts_mask[2];
+       u8     imr;
+};
+
+/* register common to both ports */
+#define RD_ISR      0x14
+#define RD_IPR      0x34
+
+#define WR_ACR      0x10
+#define WR_IMR      0x14
+#define WR_OPCR     0x34
+#define WR_OPR_SET  0x38
+#define WR_OPR_CLR  0x3C
+
+/* access common register */
+#define READ_SC(p, r)        readb((p)->membase + RD_##r)
+#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r)
+
+/* register per port */
+#define RD_PORT_MRx 0x00
+#define RD_PORT_SR  0x04
+#define RD_PORT_RHR 0x0c
+
+#define WR_PORT_MRx 0x00
+#define WR_PORT_CSR 0x04
+#define WR_PORT_CR  0x08
+#define WR_PORT_THR 0x0c
+
+/* SR bits */
+#define SR_BREAK    (1 << 7)
+#define SR_FRAME    (1 << 6)
+#define SR_PARITY   (1 << 5)
+#define SR_OVERRUN  (1 << 4)
+#define SR_TXRDY    (1 << 2)
+#define SR_RXRDY    (1 << 0)
+
+#define CR_RES_MR   (1 << 4)
+#define CR_RES_RX   (2 << 4)
+#define CR_RES_TX   (3 << 4)
+#define CR_STRT_BRK (6 << 4)
+#define CR_STOP_BRK (7 << 4)
+#define CR_DIS_TX   (1 << 3)
+#define CR_ENA_TX   (1 << 2)
+#define CR_DIS_RX   (1 << 1)
+#define CR_ENA_RX   (1 << 0)
+
+/* ISR bits */
+#define ISR_RXRDYB  (1 << 5)
+#define ISR_TXRDYB  (1 << 4)
+#define ISR_RXRDYA  (1 << 1)
+#define ISR_TXRDYA  (1 << 0)
+
+/* IMR bits */
+#define IMR_RXRDY   (1 << 1)
+#define IMR_TXRDY   (1 << 0)
+
+/* access port register */
+static inline u8 read_sc_port(struct uart_port *p, u8 reg)
+{
+       return readb(p->membase + p->line * 0x20 + reg);
+}
+
+static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
+{
+       writeb(val, p->membase + p->line * 0x20 + reg);
+}
+
+#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r)
+#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
+
+static void sc26xx_enable_irq(struct uart_port *port, int mask)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       up->imr |= mask << (line * 4);
+       WRITE_SC(port, IMR, up->imr);
+}
+
+static void sc26xx_disable_irq(struct uart_port *port, int mask)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       up->imr &= ~(mask << (line * 4));
+       WRITE_SC(port, IMR, up->imr);
+}
+
+static struct tty_struct *receive_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = NULL;
+       int limit = 10000;
+       unsigned char ch;
+       char flag;
+       u8 status;
+
+       if (port->info != NULL)         /* Unopened serial console */
+               tty = port->info->tty;
+
+       while (limit-- > 0) {
+               status = READ_SC_PORT(port, SR);
+               if (!(status & SR_RXRDY))
+                       break;
+               ch = READ_SC_PORT(port, RHR);
+
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (unlikely(status & (SR_BREAK | SR_FRAME |
+                                      SR_PARITY | SR_OVERRUN))) {
+                       if (status & SR_BREAK) {
+                               status &= ~(SR_PARITY | SR_FRAME);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       } else if (status & SR_PARITY)
+                               port->icount.parity++;
+                       else if (status & SR_FRAME)
+                               port->icount.frame++;
+                       if (status & SR_OVERRUN)
+                               port->icount.overrun++;
+
+                       status &= port->read_status_mask;
+                       if (status & SR_BREAK)
+                               flag = TTY_BREAK;
+                       else if (status & SR_PARITY)
+                               flag = TTY_PARITY;
+                       else if (status & SR_FRAME)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+
+               if (status & port->ignore_status_mask)
+                       continue;
+
+               tty_insert_flip_char(tty, ch, flag);
+       }
+       return tty;
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+
+       if (!port->info)
+               return;
+
+       xmit = &port->info->xmit;
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               sc26xx_disable_irq(port, IMR_TXRDY);
+               return;
+       }
+       while (!uart_circ_empty(xmit)) {
+               if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
+                       break;
+
+               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
+{
+       struct uart_sc26xx_port *up = dev_id;
+       struct tty_struct *tty;
+       unsigned long flags;
+       u8 isr;
+
+       spin_lock_irqsave(&up->port[0].lock, flags);
+
+       tty = NULL;
+       isr = READ_SC(&up->port[0], ISR);
+       if (isr & ISR_TXRDYA)
+           transmit_chars(&up->port[0]);
+       if (isr & ISR_RXRDYA)
+           tty = receive_chars(&up->port[0]);
+
+       spin_unlock(&up->port[0].lock);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       spin_lock(&up->port[1].lock);
+
+       tty = NULL;
+       if (isr & ISR_TXRDYB)
+           transmit_chars(&up->port[1]);
+       if (isr & ISR_RXRDYB)
+           tty = receive_chars(&up->port[1]);
+
+       spin_unlock_irqrestore(&up->port[1].lock, flags);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int sc26xx_tx_empty(struct uart_port *port)
+{
+       return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       if (up->dtr_mask[line]) {
+               if (mctrl & TIOCM_DTR)
+                       WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
+               else
+                       WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
+       }
+       if (up->rts_mask[line]) {
+               if (mctrl & TIOCM_RTS)
+                       WRITE_SC(port, OPR_SET, up->rts_mask[line]);
+               else
+                       WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
+       }
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int sc26xx_get_mctrl(struct uart_port *port)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+       unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
+       u8 ipr;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+       ipr = READ_SC(port, IPR) ^ 0xff;
+
+       if (up->dsr_mask[line]) {
+               mctrl &= ~TIOCM_DSR;
+               mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
+       }
+       if (up->cts_mask[line]) {
+               mctrl &= ~TIOCM_CTS;
+               mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
+       }
+       if (up->dcd_mask[line]) {
+               mctrl &= ~TIOCM_CAR;
+               mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
+       }
+       if (up->ri_mask[line]) {
+               mctrl &= ~TIOCM_RNG;
+               mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
+       }
+       return mctrl;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_stop_tx(struct uart_port *port)
+{
+       return;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_start_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->info->xmit;
+
+       while (!uart_circ_empty(xmit)) {
+               if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
+                       sc26xx_enable_irq(port, IMR_TXRDY);
+                       break;
+               }
+               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_stop_rx(struct uart_port *port)
+{
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_enable_ms(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sc26xx_break_ctl(struct uart_port *port, int break_state)
+{
+       if (break_state == -1)
+               WRITE_SC_PORT(port, CR, CR_STRT_BRK);
+       else
+               WRITE_SC_PORT(port, CR, CR_STOP_BRK);
+}
+
+/* port->lock is not held.  */
+static int sc26xx_startup(struct uart_port *port)
+{
+       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+       WRITE_SC(port, OPCR, 0);
+
+       /* reset tx and rx */
+       WRITE_SC_PORT(port, CR, CR_RES_RX);
+       WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+       /* start rx/tx */
+       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+
+       /* enable irqs */
+       sc26xx_enable_irq(port, IMR_RXRDY);
+       return 0;
+}
+
+/* port->lock is not held.  */
+static void sc26xx_shutdown(struct uart_port *port)
+{
+       /* disable interrupst */
+       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+
+       /* stop tx/rx */
+       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+}
+
+/* port->lock is not held.  */
+static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       unsigned int quot = uart_get_divisor(port, baud);
+       unsigned int iflag, cflag;
+       unsigned long flags;
+       u8 mr1, mr2, csr;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+               udelay(2);
+
+       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+
+       iflag = termios->c_iflag;
+       cflag = termios->c_cflag;
+
+       port->read_status_mask = SR_OVERRUN;
+       if (iflag & INPCK)
+               port->read_status_mask |= SR_PARITY | SR_FRAME;
+       if (iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= SR_BREAK;
+
+       port->ignore_status_mask = 0;
+       if (iflag & IGNBRK)
+               port->ignore_status_mask |= SR_BREAK;
+       if ((cflag & CREAD) == 0)
+               port->ignore_status_mask |= SR_BREAK | SR_FRAME |
+                                           SR_PARITY | SR_OVERRUN;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               mr1 = 0x00;
+               break;
+       case CS6:
+               mr1 = 0x01;
+               break;
+       case CS7:
+               mr1 = 0x02;
+               break;
+       default:
+       case CS8:
+               mr1 = 0x03;
+               break;
+       }
+       mr2 = 0x07;
+       if (cflag & CSTOPB)
+               mr2 = 0x0f;
+       if (cflag & PARENB) {
+               if (cflag & PARODD)
+                       mr1 |= (1 << 2);
+       } else
+               mr1 |= (2 << 3);
+
+       switch (baud) {
+       case 50:
+               csr = 0x00;
+               break;
+       case 110:
+               csr = 0x11;
+               break;
+       case 134:
+               csr = 0x22;
+               break;
+       case 200:
+               csr = 0x33;
+               break;
+       case 300:
+               csr = 0x44;
+               break;
+       case 600:
+               csr = 0x55;
+               break;
+       case 1200:
+               csr = 0x66;
+               break;
+       case 2400:
+               csr = 0x88;
+               break;
+       case 4800:
+               csr = 0x99;
+               break;
+       default:
+       case 9600:
+               csr = 0xbb;
+               break;
+       case 19200:
+               csr = 0xcc;
+               break;
+       }
+
+       WRITE_SC_PORT(port, CR, CR_RES_MR);
+       WRITE_SC_PORT(port, MRx, mr1);
+       WRITE_SC_PORT(port, MRx, mr2);
+
+       WRITE_SC(port, ACR, 0x80);
+       WRITE_SC_PORT(port, CSR, csr);
+
+       /* reset tx and rx */
+       WRITE_SC_PORT(port, CR, CR_RES_RX);
+       WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+               udelay(2);
+
+       /* XXX */
+       uart_update_timeout(port, cflag,
+                           (port->uartclk / (16 * quot)));
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sc26xx_type(struct uart_port *port)
+{
+       return "SC26XX";
+}
+
+static void sc26xx_release_port(struct uart_port *port)
+{
+}
+
+static int sc26xx_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sc26xx_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops sc26xx_ops = {
+       .tx_empty       = sc26xx_tx_empty,
+       .set_mctrl      = sc26xx_set_mctrl,
+       .get_mctrl      = sc26xx_get_mctrl,
+       .stop_tx        = sc26xx_stop_tx,
+       .start_tx       = sc26xx_start_tx,
+       .stop_rx        = sc26xx_stop_rx,
+       .enable_ms      = sc26xx_enable_ms,
+       .break_ctl      = sc26xx_break_ctl,
+       .startup        = sc26xx_startup,
+       .shutdown       = sc26xx_shutdown,
+       .set_termios    = sc26xx_set_termios,
+       .type           = sc26xx_type,
+       .release_port   = sc26xx_release_port,
+       .request_port   = sc26xx_request_port,
+       .config_port    = sc26xx_config_port,
+       .verify_port    = sc26xx_verify_port,
+};
+
+static struct uart_port *sc26xx_port;
+
+#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
+static void sc26xx_console_putchar(struct uart_port *port, char c)
+{
+       unsigned long flags;
+       int limit = 1000000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (limit-- > 0) {
+               if (READ_SC_PORT(port, SR) & SR_TXRDY) {
+                       WRITE_SC_PORT(port, THR, c);
+                       break;
+               }
+               udelay(2);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
+{
+       struct uart_port *port = sc26xx_port;
+       int i;
+
+       for (i = 0; i < n; i++) {
+               if (*s == '\n')
+                       sc26xx_console_putchar(port, '\r');
+               sc26xx_console_putchar(port, *s++);
+       }
+}
+
+static int __init sc26xx_console_setup(struct console *con, char *options)
+{
+       struct uart_port *port = sc26xx_port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (port->type != PORT_SC26XX)
+               return -1;
+
+       printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver sc26xx_reg;
+static struct console sc26xx_console = {
+       .name   =       "ttySC",
+       .write  =       sc26xx_console_write,
+       .device =       uart_console_device,
+       .setup  =       sc26xx_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sc26xx_reg,
+};
+#define SC26XX_CONSOLE   &sc26xx_console
+#else
+#define SC26XX_CONSOLE   NULL
+#endif
+
+static struct uart_driver sc26xx_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "SC26xx",
+       .dev_name               = "ttySC",
+       .major                  = SC26XX_MAJOR,
+       .minor                  = SC26XX_MINOR_START,
+       .nr                     = SC26XX_NR,
+       .cons                   = SC26XX_CONSOLE,
+};
+
+static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
+{
+       unsigned int bit = (flags >> bitpos) & 15;
+
+       return bit ? (1 << (bit - 1)) : 0;
+}
+
+static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
+                                       int line, unsigned int data)
+{
+       up->dtr_mask[line] = sc26xx_flags2mask(data,  0);
+       up->rts_mask[line] = sc26xx_flags2mask(data,  4);
+       up->dsr_mask[line] = sc26xx_flags2mask(data,  8);
+       up->cts_mask[line] = sc26xx_flags2mask(data, 12);
+       up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
+       up->ri_mask[line]  = sc26xx_flags2mask(data, 20);
+}
+
+static int __devinit sc26xx_probe(struct platform_device *dev)
+{
+       struct resource *res;
+       struct uart_sc26xx_port *up;
+       unsigned int *sc26xx_data = dev->dev.platform_data;
+       int err;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       up = kzalloc(sizeof *up, GFP_KERNEL);
+       if (unlikely(!up))
+               return -ENOMEM;
+
+       up->port[0].line = 0;
+       up->port[0].ops = &sc26xx_ops;
+       up->port[0].type = PORT_SC26XX;
+       up->port[0].uartclk = (29491200 / 16); /* arbitrary */
+
+       up->port[0].mapbase = res->start;
+       up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
+       up->port[0].iotype = UPIO_MEM;
+       up->port[0].irq = platform_get_irq(dev, 0);
+
+       up->port[0].dev = &dev->dev;
+
+       sc26xx_init_masks(up, 0, sc26xx_data[0]);
+
+       sc26xx_port = &up->port[0];
+
+       up->port[1].line = 1;
+       up->port[1].ops = &sc26xx_ops;
+       up->port[1].type = PORT_SC26XX;
+       up->port[1].uartclk = (29491200 / 16); /* arbitrary */
+
+       up->port[1].mapbase = up->port[0].mapbase;
+       up->port[1].membase = up->port[0].membase;
+       up->port[1].iotype = UPIO_MEM;
+       up->port[1].irq = up->port[0].irq;
+
+       up->port[1].dev = &dev->dev;
+
+       sc26xx_init_masks(up, 1, sc26xx_data[1]);
+
+       err = uart_register_driver(&sc26xx_reg);
+       if (err)
+               goto out_free_port;
+
+       sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
+
+       err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
+       if (err)
+               goto out_unregister_driver;
+
+       err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
+       if (err)
+               goto out_remove_port0;
+
+       err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
+       if (err)
+               goto out_remove_ports;
+
+       dev_set_drvdata(&dev->dev, up);
+       return 0;
+
+out_remove_ports:
+       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+out_remove_port0:
+       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+
+out_unregister_driver:
+       uart_unregister_driver(&sc26xx_reg);
+
+out_free_port:
+       kfree(up);
+       sc26xx_port = NULL;
+       return err;
+}
+
+
+static int __exit sc26xx_driver_remove(struct platform_device *dev)
+{
+       struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
+
+       free_irq(up->port[0].irq, up);
+
+       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+
+       uart_unregister_driver(&sc26xx_reg);
+
+       kfree(up);
+       sc26xx_port = NULL;
+
+       dev_set_drvdata(&dev->dev, NULL);
+       return 0;
+}
+
+static struct platform_driver sc26xx_driver = {
+       .probe  = sc26xx_probe,
+       .remove = __devexit_p(sc26xx_driver_remove),
+       .driver = {
+               .name   = "SC26xx",
+       },
+};
+
+static int __init sc26xx_init(void)
+{
+       return platform_driver_register(&sc26xx_driver);
+}
+
+static void __exit sc26xx_exit(void)
+{
+       platform_driver_unregister(&sc26xx_driver);
+}
+
+module_init(sc26xx_init);
+module_exit(sc26xx_exit);
+
+
+MODULE_AUTHOR("Thomas Bogendörfer");
+MODULE_DESCRIPTION("SC681/SC2692 serial driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
index 1a7bccebd50322ad0b3201864e00bea9006ea075..4e06ab6bcb6e80c15c5f71b723e912f9e7f53d08 100644 (file)
@@ -153,7 +153,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
 
 static irqreturn_t ulite_isr(int irq, void *dev_id)
 {
-       struct uart_port *port = (struct uart_port *)dev_id;
+       struct uart_port *port = dev_id;
        int busy;
 
        do {
index aaaea81e412aa81abe5f2f1ced1b89152044c4a3..d8107890db152c789a764248a9d9a1078484ee02 100644 (file)
@@ -144,10 +144,10 @@ config SPI_OMAP_UWIRE
          This hooks up to the MicroWire controller on OMAP1 chips.
 
 config SPI_OMAP24XX
-       tristate "McSPI driver for OMAP24xx"
-       depends on SPI_MASTER && ARCH_OMAP24XX
+       tristate "McSPI driver for OMAP24xx/OMAP34xx"
+       depends on SPI_MASTER && (ARCH_OMAP24XX || ARCH_OMAP34XX)
        help
-         SPI master controller for OMAP24xx Multichannel SPI
+         SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
          (McSPI) modules.
 
 config SPI_PXA2XX
@@ -176,6 +176,13 @@ config SPI_S3C24XX_GPIO
          the inbuilt hardware cannot provide the transfer mode, or
          where the board is using non hardware connected pins.
 
+config SPI_SH_SCI
+       tristate "SuperH SCI SPI controller"
+       depends on SPI_MASTER && SUPERH
+       select SPI_BITBANG
+       help
+         SPI driver for SuperH SCI blocks.
+
 config SPI_TXX9
        tristate "Toshiba TXx9 SPI controller"
        depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX
index 41fbac45c323bc25bccd3a9d364279781826d290..7fca043ce723a77698d1946e1f88947c9a1d5008 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO)                += spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx.o
 obj-$(CONFIG_SPI_TXX9)                 += spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)               += xilinx_spi.o
+obj-$(CONFIG_SPI_SH_SCI)               += spi_sh_sci.o
 #      ... add above this line ...
 
 # SPI protocol drivers (device/link on bus)
index ff10808183a36f4e9d642469e42653d50f13ca24..293b7cab3e57021afcfeddcd2a5b007fbfba229a 100644 (file)
@@ -51,7 +51,9 @@ struct atmel_spi {
        u8                      stopping;
        struct list_head        queue;
        struct spi_transfer     *current_transfer;
-       unsigned long           remaining_bytes;
+       unsigned long           current_remaining_bytes;
+       struct spi_transfer     *next_transfer;
+       unsigned long           next_remaining_bytes;
 
        void                    *buffer;
        dma_addr_t              buffer_dma;
@@ -121,6 +123,48 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
                gpio_set_value(gpio, !active);
 }
 
+static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
+                                       struct spi_transfer *xfer)
+{
+       return msg->transfers.prev == &xfer->transfer_list;
+}
+
+static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
+{
+       return xfer->delay_usecs == 0 && !xfer->cs_change;
+}
+
+static void atmel_spi_next_xfer_data(struct spi_master *master,
+                               struct spi_transfer *xfer,
+                               dma_addr_t *tx_dma,
+                               dma_addr_t *rx_dma,
+                               u32 *plen)
+{
+       struct atmel_spi        *as = spi_master_get_devdata(master);
+       u32                     len = *plen;
+
+       /* use scratch buffer only when rx or tx data is unspecified */
+       if (xfer->rx_buf)
+               *rx_dma = xfer->rx_dma + xfer->len - len;
+       else {
+               *rx_dma = as->buffer_dma;
+               if (len > BUFFER_SIZE)
+                       len = BUFFER_SIZE;
+       }
+       if (xfer->tx_buf)
+               *tx_dma = xfer->tx_dma + xfer->len - len;
+       else {
+               *tx_dma = as->buffer_dma;
+               if (len > BUFFER_SIZE)
+                       len = BUFFER_SIZE;
+               memset(as->buffer, 0, len);
+               dma_sync_single_for_device(&as->pdev->dev,
+                               as->buffer_dma, len, DMA_TO_DEVICE);
+       }
+
+       *plen = len;
+}
+
 /*
  * Submit next transfer for DMA.
  * lock is held, spi irq is blocked
@@ -130,53 +174,78 @@ static void atmel_spi_next_xfer(struct spi_master *master,
 {
        struct atmel_spi        *as = spi_master_get_devdata(master);
        struct spi_transfer     *xfer;
-       u32                     len;
+       u32                     len, remaining, total;
        dma_addr_t              tx_dma, rx_dma;
 
-       xfer = as->current_transfer;
-       if (!xfer || as->remaining_bytes == 0) {
-               if (xfer)
-                       xfer = list_entry(xfer->transfer_list.next,
-                                       struct spi_transfer, transfer_list);
-               else
-                       xfer = list_entry(msg->transfers.next,
-                                       struct spi_transfer, transfer_list);
-               as->remaining_bytes = xfer->len;
-               as->current_transfer = xfer;
-       }
+       if (!as->current_transfer)
+               xfer = list_entry(msg->transfers.next,
+                               struct spi_transfer, transfer_list);
+       else if (!as->next_transfer)
+               xfer = list_entry(as->current_transfer->transfer_list.next,
+                               struct spi_transfer, transfer_list);
+       else
+               xfer = NULL;
 
-       len = as->remaining_bytes;
+       if (xfer) {
+               len = xfer->len;
+               atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+               remaining = xfer->len - len;
 
-       tx_dma = xfer->tx_dma + xfer->len - len;
-       rx_dma = xfer->rx_dma + xfer->len - len;
+               spi_writel(as, RPR, rx_dma);
+               spi_writel(as, TPR, tx_dma);
 
-       /* use scratch buffer only when rx or tx data is unspecified */
-       if (!xfer->rx_buf) {
-               rx_dma = as->buffer_dma;
-               if (len > BUFFER_SIZE)
-                       len = BUFFER_SIZE;
-       }
-       if (!xfer->tx_buf) {
-               tx_dma = as->buffer_dma;
-               if (len > BUFFER_SIZE)
-                       len = BUFFER_SIZE;
-               memset(as->buffer, 0, len);
-               dma_sync_single_for_device(&as->pdev->dev,
-                               as->buffer_dma, len, DMA_TO_DEVICE);
+               if (msg->spi->bits_per_word > 8)
+                       len >>= 1;
+               spi_writel(as, RCR, len);
+               spi_writel(as, TCR, len);
+
+               dev_dbg(&msg->spi->dev,
+                       "  start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+                       xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+                       xfer->rx_buf, xfer->rx_dma);
+       } else {
+               xfer = as->next_transfer;
+               remaining = as->next_remaining_bytes;
        }
 
-       spi_writel(as, RPR, rx_dma);
-       spi_writel(as, TPR, tx_dma);
+       as->current_transfer = xfer;
+       as->current_remaining_bytes = remaining;
 
-       as->remaining_bytes -= len;
-       if (msg->spi->bits_per_word > 8)
-               len >>= 1;
+       if (remaining > 0)
+               len = remaining;
+       else if (!atmel_spi_xfer_is_last(msg, xfer)
+                       && atmel_spi_xfer_can_be_chained(xfer)) {
+               xfer = list_entry(xfer->transfer_list.next,
+                               struct spi_transfer, transfer_list);
+               len = xfer->len;
+       } else
+               xfer = NULL;
 
-       /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
-        * mechanism might help avoid the IRQ latency between transfers
-        * (and improve the nCS0 errata handling on at91rm9200 chips)
-        *
-        * We're also waiting for ENDRX before we start the next
+       as->next_transfer = xfer;
+
+       if (xfer) {
+               total = len;
+               atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+               as->next_remaining_bytes = total - len;
+
+               spi_writel(as, RNPR, rx_dma);
+               spi_writel(as, TNPR, tx_dma);
+
+               if (msg->spi->bits_per_word > 8)
+                       len >>= 1;
+               spi_writel(as, RNCR, len);
+               spi_writel(as, TNCR, len);
+
+               dev_dbg(&msg->spi->dev,
+                       "  next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+                       xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+                       xfer->rx_buf, xfer->rx_dma);
+       } else {
+               spi_writel(as, RNCR, 0);
+               spi_writel(as, TNCR, 0);
+       }
+
+       /* REVISIT: We're waiting for ENDRX before we start the next
         * transfer because we need to handle some difficult timing
         * issues otherwise. If we wait for ENDTX in one transfer and
         * then starts waiting for ENDRX in the next, it's difficult
@@ -186,17 +255,7 @@ static void atmel_spi_next_xfer(struct spi_master *master,
         *
         * It should be doable, though. Just not now...
         */
-       spi_writel(as, TNCR, 0);
-       spi_writel(as, RNCR, 0);
        spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
-
-       dev_dbg(&msg->spi->dev,
-               "  start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n",
-               xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
-               xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
-
-       spi_writel(as, RCR, len);
-       spi_writel(as, TCR, len);
        spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
 }
 
@@ -294,6 +353,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
        spin_lock(&as->lock);
 
        as->current_transfer = NULL;
+       as->next_transfer = NULL;
 
        /* continue if needed */
        if (list_empty(&as->queue) || as->stopping)
@@ -377,7 +437,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
 
                spi_writel(as, IDR, pending);
 
-               if (as->remaining_bytes == 0) {
+               if (as->current_remaining_bytes == 0) {
                        msg->actual_length += xfer->len;
 
                        if (!msg->is_dma_mapped)
@@ -387,7 +447,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
                        if (xfer->delay_usecs)
                                udelay(xfer->delay_usecs);
 
-                       if (msg->transfers.prev == &xfer->transfer_list) {
+                       if (atmel_spi_xfer_is_last(msg, xfer)) {
                                /* report completed message */
                                atmel_spi_msg_done(master, as, msg, 0,
                                                xfer->cs_change);
@@ -490,9 +550,14 @@ static int atmel_spi_setup(struct spi_device *spi)
        if (!(spi->mode & SPI_CPHA))
                csr |= SPI_BIT(NCPHA);
 
-       /* TODO: DLYBS and DLYBCT */
-       csr |= SPI_BF(DLYBS, 10);
-       csr |= SPI_BF(DLYBCT, 10);
+       /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
+        *
+        * DLYBCT would add delays between words, slowing down transfers.
+        * It could potentially be useful to cope with DMA bottlenecks, but
+        * in those cases it's probably best to just use a lower bitrate.
+        */
+       csr |= SPI_BF(DLYBS, 0);
+       csr |= SPI_BF(DLYBCT, 0);
 
        /* chipselect must have been muxed as GPIO (e.g. in board setup) */
        npcs_pin = (unsigned int)spi->controller_data;
index ea61724ae2256fe33035f77e29cce9a0a67eb48a..a6ba11afb03f798bb7f8520c352b419ff6bb119d 100644 (file)
@@ -915,6 +915,28 @@ static u8 __initdata spi2_txdma_id[] = {
        OMAP24XX_DMA_SPI2_TX1,
 };
 
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+static u8 __initdata spi3_rxdma_id[] = {
+       OMAP24XX_DMA_SPI3_RX0,
+       OMAP24XX_DMA_SPI3_RX1,
+};
+
+static u8 __initdata spi3_txdma_id[] = {
+       OMAP24XX_DMA_SPI3_TX0,
+       OMAP24XX_DMA_SPI3_TX1,
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static u8 __initdata spi4_rxdma_id[] = {
+       OMAP34XX_DMA_SPI4_RX0,
+};
+
+static u8 __initdata spi4_txdma_id[] = {
+       OMAP34XX_DMA_SPI4_TX0,
+};
+#endif
+
 static int __init omap2_mcspi_probe(struct platform_device *pdev)
 {
        struct spi_master       *master;
@@ -935,7 +957,20 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
                txdma_id = spi2_txdma_id;
                num_chipselect = 2;
                break;
-       /* REVISIT omap2430 has a third McSPI ... */
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+       case 3:
+               rxdma_id = spi3_rxdma_id;
+               txdma_id = spi3_txdma_id;
+               num_chipselect = 2;
+               break;
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+       case 4:
+               rxdma_id = spi4_rxdma_id;
+               txdma_id = spi4_txdma_id;
+               num_chipselect = 1;
+               break;
+#endif
        default:
                return -EINVAL;
        }
index eb817b8eb02439eeb12944e89fc2f55749adc009..365e0e355aea302e684451592d9315862f565275 100644 (file)
@@ -1526,17 +1526,6 @@ static void pxa2xx_spi_shutdown(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int suspend_devices(struct device *dev, void *pm_message)
-{
-       pm_message_t *state = pm_message;
-
-       if (dev->power.power_state.event != state->event) {
-               dev_warn(dev, "pm state does not match request\n");
-               return -1;
-       }
-
-       return 0;
-}
 
 static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
 {
@@ -1544,12 +1533,6 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
        struct ssp_device *ssp = drv_data->ssp;
        int status = 0;
 
-       /* Check all childern for current power state */
-       if (device_for_each_child(&pdev->dev, &state, suspend_devices) != 0) {
-               dev_warn(&pdev->dev, "suspend aborted\n");
-               return -1;
-       }
-
        status = stop_queue(drv_data);
        if (status != 0)
                return status;
index 682a6a48fec31e989dee472420cd37bc766c4b9f..1ad12afc6ba0ace916c817c571b265dc49cc1398 100644 (file)
@@ -18,7 +18,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/autoconf.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -77,39 +76,33 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 #ifdef CONFIG_PM
 
-/*
- * NOTE:  the suspend() method for an spi_master controller driver
- * should verify that all its child devices are marked as suspended;
- * suspend requests delivered through sysfs power/state files don't
- * enforce such constraints.
- */
 static int spi_suspend(struct device *dev, pm_message_t message)
 {
-       int                     value;
+       int                     value = 0;
        struct spi_driver       *drv = to_spi_driver(dev->driver);
 
-       if (!drv || !drv->suspend)
-               return 0;
-
        /* suspend will stop irqs and dma; no more i/o */
-       value = drv->suspend(to_spi_device(dev), message);
-       if (value == 0)
-               dev->power.power_state = message;
+       if (drv) {
+               if (drv->suspend)
+                       value = drv->suspend(to_spi_device(dev), message);
+               else
+                       dev_dbg(dev, "... can't suspend\n");
+       }
        return value;
 }
 
 static int spi_resume(struct device *dev)
 {
-       int                     value;
+       int                     value = 0;
        struct spi_driver       *drv = to_spi_driver(dev->driver);
 
-       if (!drv || !drv->resume)
-               return 0;
-
        /* resume may restart the i/o queue */
-       value = drv->resume(to_spi_device(dev));
-       if (value == 0)
-               dev->power.power_state = PMSG_ON;
+       if (drv) {
+               if (drv->resume)
+                       value = drv->resume(to_spi_device(dev));
+               else
+                       dev_dbg(dev, "... can't resume\n");
+       }
        return value;
 }
 
index 7ef39a6e8c065afc97bba75dd26b2b691be95e4b..d853fceb6bf01bebfa9f3386a6dee184dbc21c20 100644 (file)
@@ -1,37 +1,11 @@
 /*
- * File:       drivers/spi/bfin5xx_spi.c
- * Maintainer:
- *             Bryan Wu <bryan.wu@analog.com>
- * Original Author:
- *             Luke Yang (Analog Devices Inc.)
- *
- * Created:    March. 10th 2006
- * Description:        SPI controller driver for Blackfin BF5xx
- * Bugs:       Enter bugs at http://blackfin.uclinux.org/
- *
- * Modified:
- *     March 10, 2006  bfin5xx_spi.c Created. (Luke Yang)
- *      August 7, 2006  added full duplex mode (Axel Weiss & Luke Yang)
- *      July  17, 2007  add support for BF54x SPI0 controller (Bryan Wu)
- *      July  30, 2007  add platfrom_resource interface to support multi-port
- *                      SPI controller (Bryan Wu)
+ * Blackfin On-Chip SPI Driver
  *
  * Copyright 2004-2007 Analog Devices 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, 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.
+ * Enter bugs at http://blackfin.uclinux.org/
  *
- * You should have received a copy of the GNU General Public License
- * along with this program ;  see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/init.h>
@@ -223,10 +197,9 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
 #define MAX_SPI_SSEL   7
 
 /* stop controller and re-config current chip*/
-static int restore_state(struct driver_data *drv_data)
+static void restore_state(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
-       int ret = 0;
 
        /* Clear status and disable clock */
        write_STAT(drv_data, BIT_STAT_CLR);
@@ -239,13 +212,6 @@ static int restore_state(struct driver_data *drv_data)
 
        bfin_spi_enable(drv_data);
        cs_active(drv_data, chip);
-
-       if (ret)
-               dev_dbg(&drv_data->pdev->dev,
-                       ": request chip select number %d failed\n",
-                       chip->chip_select_num);
-
-       return ret;
 }
 
 /* used to kick off transfer in rx mode */
@@ -286,32 +252,30 @@ static void u8_writer(struct driver_data *drv_data)
        dev_dbg(&drv_data->pdev->dev,
                "cr8-s is 0x%x\n", read_STAT(drv_data));
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
                while (read_STAT(drv_data) & BIT_STAT_TXS)
                        cpu_relax();
                ++drv_data->tx;
        }
+
+       /* poll for SPI completion before return */
+       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+               cpu_relax();
 }
 
 static void u8_cs_chg_writer(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
                while (read_STAT(drv_data) & BIT_STAT_TXS)
                        cpu_relax();
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+                       cpu_relax();
 
                cs_deactive(drv_data, chip);
 
@@ -350,43 +314,28 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
-       /* clear TDBR buffer before read(else it will be shifted out) */
-       write_TDBR(drv_data, 0xFFFF);
+       while (drv_data->rx < drv_data->rx_end) {
+               cs_active(drv_data, chip);
+               read_RDBR(drv_data);    /* kick off */
 
-       cs_active(drv_data, chip);
-       dummy_read(drv_data);
+               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+                       cpu_relax();
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+                       cpu_relax();
 
-       while (drv_data->rx < drv_data->rx_end - 1) {
+               *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
                cs_deactive(drv_data, chip);
 
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               cs_active(drv_data, chip);
-               *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
                ++drv_data->rx;
        }
-       cs_deactive(drv_data, chip);
-
-       while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-               cpu_relax();
-       *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
-       ++drv_data->rx;
 }
 
 static void u8_duplex(struct driver_data *drv_data)
 {
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        /* in duplex mode, clk is triggered by writing of TDBR */
        while (drv_data->rx < drv_data->rx_end) {
                write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -400,15 +349,12 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->rx < drv_data->rx_end) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -426,32 +372,30 @@ static void u16_writer(struct driver_data *drv_data)
        dev_dbg(&drv_data->pdev->dev,
                "cr16 is 0x%x\n", read_STAT(drv_data));
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
                while ((read_STAT(drv_data) & BIT_STAT_TXS))
                        cpu_relax();
                drv_data->tx += 2;
        }
+
+       /* poll for SPI completion before return */
+       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+               cpu_relax();
 }
 
 static void u16_cs_chg_writer(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
                while ((read_STAT(drv_data) & BIT_STAT_TXS))
                        cpu_relax();
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+                       cpu_relax();
 
                cs_deactive(drv_data, chip);
 
@@ -519,14 +463,10 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
 
 static void u16_duplex(struct driver_data *drv_data)
 {
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        /* in duplex mode, clk is triggered by writing of TDBR */
        while (drv_data->tx < drv_data->tx_end) {
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -540,15 +480,11 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -616,7 +552,7 @@ static void giveback(struct driver_data *drv_data)
 
 static irqreturn_t dma_irq_handler(int irq, void *dev_id)
 {
-       struct driver_data *drv_data = (struct driver_data *)dev_id;
+       struct driver_data *drv_data = dev_id;
        struct chip_data *chip = drv_data->cur_chip;
        struct spi_message *msg = drv_data->cur_msg;
 
@@ -978,10 +914,7 @@ static void pump_messages(struct work_struct *work)
 
        /* Setup the SSP using the per chip configuration */
        drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
-       if (restore_state(drv_data)) {
-               spin_unlock_irqrestore(&drv_data->lock, flags);
-               return;
-       };
+       restore_state(drv_data);
 
        list_del_init(&drv_data->cur_msg->queue);
 
@@ -1187,7 +1120,7 @@ static int setup(struct spi_device *spi)
        if ((chip->chip_select_num > 0)
                && (chip->chip_select_num <= spi->master->num_chipselect))
                peripheral_request(ssel[spi->master->bus_num]
-                       [chip->chip_select_num-1], DRV_NAME);
+                       [chip->chip_select_num-1], spi->modalias);
 
        cs_deactive(drv_data, chip);
 
index 639963eb1ac124d21d53628e052e10ac5be3f59d..1b0647124933cc473ef532e3a59265f6f2dd6a2c 100644 (file)
@@ -1686,17 +1686,6 @@ static void spi_imx_shutdown(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int suspend_devices(struct device *dev, void *pm_message)
-{
-       pm_message_t *state = pm_message;
-
-       if (dev->power.power_state.event != state->event) {
-               dev_warn(dev, "pm state does not match request\n");
-               return -1;
-       }
-
-       return 0;
-}
 
 static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state)
 {
index 89d6685a5ca4860594773a346e37dbad40021762..6e834b8b9d2785f51427cd11d3a051e9e9471b03 100644 (file)
@@ -237,10 +237,8 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
 {
        struct s3c24xx_spi *hw;
        struct spi_master *master;
-       struct spi_board_info *bi;
        struct resource *res;
        int err = 0;
-       int i;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
        if (master == NULL) {
@@ -348,16 +346,6 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
                goto err_register;
        }
 
-       /* register all the devices associated */
-
-       bi = &hw->pdata->board_info[0];
-       for (i = 0; i < hw->pdata->board_size; i++, bi++) {
-               dev_info(hw->dev, "registering %s\n", bi->modalias);
-
-               bi->controller_data = hw;
-               spi_new_device(master, bi);
-       }
-
        return 0;
 
  err_register:
index 109d82c1abc05a9844578df75f72ad2f80af03ee..82ae7d7eca386bafffa0c7ee7eb8b4c1388630dc 100644 (file)
@@ -100,7 +100,6 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
        struct spi_master       *master;
        struct s3c2410_spigpio  *sp;
        int ret;
-       int i;
 
        master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
        if (master == NULL) {
@@ -143,17 +142,6 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
        if (ret)
                goto err_no_bitbang;
 
-       /* register the chips to go with the board */
-
-       for (i = 0; i < sp->info->board_size; i++) {
-               dev_info(&dev->dev, "registering %p: %s\n",
-                        &sp->info->board_info[i],
-                        sp->info->board_info[i].modalias);
-
-               sp->info->board_info[i].controller_data = sp;
-               spi_new_device(master, sp->info->board_info + i);
-       }
-
        return 0;
 
  err_no_bitbang:
diff --git a/drivers/spi/spi_sh_sci.c b/drivers/spi/spi_sh_sci.c
new file mode 100644 (file)
index 0000000..3dbe71b
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * SH SCI SPI interface
+ *
+ * Copyright (c) 2008 Magnus Damm
+ *
+ * Based on S3C24XX GPIO based SPI driver, which is:
+ *   Copyright (c) 2006 Ben Dooks
+ *   Copyright (c) 2006 Simtec Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/spi.h>
+#include <asm/io.h>
+
+struct sh_sci_spi {
+       struct spi_bitbang bitbang;
+
+       void __iomem *membase;
+       unsigned char val;
+       struct sh_spi_info *info;
+       struct platform_device *dev;
+};
+
+#define SCSPTR(sp)     (sp->membase + 0x1c)
+#define PIN_SCK                (1 << 2)
+#define PIN_TXD                (1 << 0)
+#define PIN_RXD                PIN_TXD
+#define PIN_INIT       ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
+
+static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
+{
+       /*
+        * We are the only user of SCSPTR so no locking is required.
+        * Reading bit 2 and 0 in SCSPTR gives pin state as input.
+        * Writing the same bits sets the output value.
+        * This makes regular read-modify-write difficult so we
+        * use sp->val to keep track of the latest register value.
+        */
+
+       if (on)
+               sp->val |= bits;
+       else
+               sp->val &= ~bits;
+
+       iowrite8(sp->val, SCSPTR(sp));
+}
+
+static inline void setsck(struct spi_device *dev, int on)
+{
+       setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
+}
+
+static inline void setmosi(struct spi_device *dev, int on)
+{
+       setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
+}
+
+static inline u32 getmiso(struct spi_device *dev)
+{
+       struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+
+       return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
+}
+
+#define spidelay(x) ndelay(x)
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
+{
+       struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+
+       if (sp->info && sp->info->chip_select)
+               (sp->info->chip_select)(sp->info, dev->chip_select, value);
+}
+
+static int sh_sci_spi_probe(struct platform_device *dev)
+{
+       struct resource *r;
+       struct spi_master *master;
+       struct sh_sci_spi *sp;
+       int ret;
+
+       master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
+       if (master == NULL) {
+               dev_err(&dev->dev, "failed to allocate spi master\n");
+               ret = -ENOMEM;
+               goto err0;
+       }
+
+       sp = spi_master_get_devdata(master);
+
+       platform_set_drvdata(dev, sp);
+       sp->info = dev->dev.platform_data;
+
+       /* setup spi bitbang adaptor */
+       sp->bitbang.master = spi_master_get(master);
+       sp->bitbang.master->bus_num = sp->info->bus_num;
+       sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
+       sp->bitbang.chipselect = sh_sci_spi_chipselect;
+
+       sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
+       sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
+       sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
+       sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
+
+       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               ret = -ENOENT;
+               goto err1;
+       }
+       sp->membase = ioremap(r->start, r->end - r->start + 1);
+       if (!sp->membase) {
+               ret = -ENXIO;
+               goto err1;
+       }
+       sp->val = ioread8(SCSPTR(sp));
+       setbits(sp, PIN_INIT, 1);
+
+       ret = spi_bitbang_start(&sp->bitbang);
+       if (!ret)
+               return 0;
+
+       setbits(sp, PIN_INIT, 0);
+       iounmap(sp->membase);
+ err1:
+       spi_master_put(sp->bitbang.master);
+ err0:
+       return ret;
+}
+
+static int sh_sci_spi_remove(struct platform_device *dev)
+{
+       struct sh_sci_spi *sp = platform_get_drvdata(dev);
+
+       iounmap(sp->membase);
+       setbits(sp, PIN_INIT, 0);
+       spi_bitbang_stop(&sp->bitbang);
+       spi_master_put(sp->bitbang.master);
+       return 0;
+}
+
+static struct platform_driver sh_sci_spi_drv = {
+       .probe          = sh_sci_spi_probe,
+       .remove         = sh_sci_spi_remove,
+       .driver         = {
+               .name   = "spi_sh_sci",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sh_sci_spi_init(void)
+{
+       return platform_driver_register(&sh_sci_spi_drv);
+}
+module_init(sh_sci_spi_init);
+
+static void __exit sh_sci_spi_exit(void)
+{
+       platform_driver_unregister(&sh_sci_spi_drv);
+}
+module_exit(sh_sci_spi_exit);
+
+MODULE_DESCRIPTION("SH SCI SPI Driver");
+MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
+MODULE_LICENSE("GPL");
index cc246faa35909116bb61d19541d47059c99ea0fb..2a77e9d42c687acc4773d68a4a2aa8b1176ff461 100644 (file)
@@ -417,30 +417,28 @@ static void uio_vma_close(struct vm_area_struct *vma)
        idev->vma_count--;
 }
 
-static struct page *uio_vma_nopage(struct vm_area_struct *vma,
-                                  unsigned long address, int *type)
+static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct uio_device *idev = vma->vm_private_data;
-       struct page* page = NOPAGE_SIGBUS;
+       struct page *page;
 
        int mi = uio_find_mem_index(vma);
        if (mi < 0)
-               return page;
+               return VM_FAULT_SIGBUS;
 
        if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
                page = virt_to_page(idev->info->mem[mi].addr);
        else
                page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
        get_page(page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return page;
+       vmf->page = page;
+       return 0;
 }
 
 static struct vm_operations_struct uio_vm_ops = {
        .open = uio_vma_open,
        .close = uio_vma_close,
-       .nopage = uio_vma_nopage,
+       .fault = uio_vma_fault,
 };
 
 static int uio_mmap_physical(struct vm_area_struct *vma)
index f8e711147501079011887cc86f65365b04b1cf46..fc65c02306ddbd6c32c2be96b80fcd630be0258a 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/backlight.h>
 
 #include <asm/arch/board.h>
 #include <asm/arch/cpu.h>
@@ -69,6 +70,107 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
 }
 #endif
 
+static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+               | ATMEL_LCDC_POL_POSITIVE
+               | ATMEL_LCDC_ENA_PWMENABLE;
+
+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+/* some bl->props field just changed */
+static int atmel_bl_update_status(struct backlight_device *bl)
+{
+       struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+       int                     power = sinfo->bl_power;
+       int                     brightness = bl->props.brightness;
+
+       /* REVISIT there may be a meaningful difference between
+        * fb_blank and power ... there seem to be some cases
+        * this doesn't handle correctly.
+        */
+       if (bl->props.fb_blank != sinfo->bl_power)
+               power = bl->props.fb_blank;
+       else if (bl->props.power != sinfo->bl_power)
+               power = bl->props.power;
+
+       if (brightness < 0 && power == FB_BLANK_UNBLANK)
+               brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+       else if (power != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+                       brightness ? contrast_ctr : 0);
+
+       bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+
+       return 0;
+}
+
+static int atmel_bl_get_brightness(struct backlight_device *bl)
+{
+       struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+
+       return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+}
+
+static struct backlight_ops atmel_lcdc_bl_ops = {
+       .update_status = atmel_bl_update_status,
+       .get_brightness = atmel_bl_get_brightness,
+};
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+       struct backlight_device *bl;
+
+       sinfo->bl_power = FB_BLANK_UNBLANK;
+
+       if (sinfo->backlight)
+               return;
+
+       bl = backlight_device_register("backlight", &sinfo->pdev->dev,
+                       sinfo, &atmel_lcdc_bl_ops);
+       if (IS_ERR(sinfo->backlight)) {
+               dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
+                               PTR_ERR(bl));
+               return;
+       }
+       sinfo->backlight = bl;
+
+       bl->props.power = FB_BLANK_UNBLANK;
+       bl->props.fb_blank = FB_BLANK_UNBLANK;
+       bl->props.max_brightness = 0xff;
+       bl->props.brightness = atmel_bl_get_brightness(bl);
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+       if (sinfo->backlight)
+               backlight_device_unregister(sinfo->backlight);
+}
+
+#else
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+       dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+}
+
+#endif
+
+static void init_contrast(struct atmel_lcdfb_info *sinfo)
+{
+       /* have some default contrast/backlight settings */
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+
+       if (sinfo->lcdcon_is_backlight)
+               init_backlight(sinfo);
+}
+
 
 static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
        .type           = FB_TYPE_PACKED_PIXELS,
@@ -203,6 +305,26 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
        var->transp.offset = var->transp.length = 0;
        var->xoffset = var->yoffset = 0;
 
+       /* Saturate vertical and horizontal timings at maximum values */
+       var->vsync_len = min_t(u32, var->vsync_len,
+                       (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+       var->upper_margin = min_t(u32, var->upper_margin,
+                       ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+       var->lower_margin = min_t(u32, var->lower_margin,
+                       ATMEL_LCDC_VFP);
+       var->right_margin = min_t(u32, var->right_margin,
+                       (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+       var->hsync_len = min_t(u32, var->hsync_len,
+                       (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+       var->left_margin = min_t(u32, var->left_margin,
+                       ATMEL_LCDC_HBP + 1);
+
+       /* Some parameters can't be zero */
+       var->vsync_len = max_t(u32, var->vsync_len, 1);
+       var->right_margin = max_t(u32, var->right_margin, 1);
+       var->hsync_len = max_t(u32, var->hsync_len, 1);
+       var->left_margin = max_t(u32, var->left_margin, 1);
+
        switch (var->bits_per_pixel) {
        case 1:
        case 2:
@@ -370,10 +492,6 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
        /* Disable all interrupts */
        lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
 
-       /* Set contrast */
-       value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
-       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
-       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
        /* ...wait for DMA engine to become idle... */
        while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
                msleep(10);
@@ -577,6 +695,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
                sinfo->default_monspecs = pdata_sinfo->default_monspecs;
                sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
                sinfo->guard_time = pdata_sinfo->guard_time;
+               sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
        } else {
                dev_err(dev, "cannot get default configuration\n");
                goto free_info;
@@ -670,6 +789,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
                goto release_mem;
        }
 
+       /* Initialize PWM for contrast or backlight ("off") */
+       init_contrast(sinfo);
+
        /* interrupt */
        ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
        if (ret) {
@@ -721,6 +843,7 @@ free_cmap:
 unregister_irqs:
        free_irq(sinfo->irq_base, info);
 unmap_mmio:
+       exit_backlight(sinfo);
        iounmap(sinfo->mmio);
 release_mem:
        release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
@@ -755,6 +878,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
        if (!sinfo)
                return 0;
 
+       exit_backlight(sinfo);
        if (sinfo->atmel_lcdfb_power_control)
                sinfo->atmel_lcdfb_power_control(0);
        unregister_framebuffer(info);
@@ -781,6 +905,9 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
 
 static struct platform_driver atmel_lcdfb_driver = {
        .remove         = __exit_p(atmel_lcdfb_remove),
+
+// FIXME need suspend, resume
+
        .driver         = {
                .name   = "atmel_lcdfb",
                .owner  = THIS_MODULE,
index 9609a6c676bea96296a89cd479216dd7c6be38fd..924e2551044aee6b1f3e84b547c702ac30690412 100644 (file)
@@ -50,6 +50,19 @@ config BACKLIGHT_CLASS_DEVICE
          To have support for your specific LCD panel you will have to
          select the proper drivers which depend on this option.
 
+config BACKLIGHT_ATMEL_LCDC
+       bool "Atmel LCDC Contrast-as-Backlight control"
+       depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
+       default y if MACH_SAM9261EK || MACH_SAM9263EK
+       help
+         This provides a backlight control internal to the Atmel LCDC
+         driver.  If the LCD "contrast control" on your board is wired
+         so it controls the backlight brightness, select this option to
+         export this as a PWM-based backlight control.
+
+         If in doubt, it's safe to enable this option; it doesn't kick
+         in unless the board's description says it's wired that way.
+
 config BACKLIGHT_CORGI
        tristate "Generic (aka Sharp Corgi) Backlight Driver"
        depends on BACKLIGHT_CLASS_DEVICE
index c8e7427a0bc8732a18122a16e966236ebff4895a..0ce791e6f79cee17b7c16072042d6b5d5b26206c 100644 (file)
@@ -498,8 +498,7 @@ static struct lcd_device *lcd_dev;
 
 static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
 {
-
-       /*struct bfin_bf54xfb_info *info = (struct bfin_bf54xfb_info *)dev_id;*/
+       /*struct bfin_bf54xfb_info *info = dev_id;*/
 
        u16 status = bfin_read_EPPI0_STATUS();
 
index 308850df16fea8bafaa7c610cf954f87fc7cd866..69864b1b3f9ee149aa7f2adbf2676574d09c8d49 100644 (file)
@@ -63,7 +63,7 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
        struct fb_fillrect region;
 
-       region.color = attr_bgcol_ec(bgshift, vc);
+       region.color = attr_bgcol_ec(bgshift, vc, info);
        region.dx = sx * vc->vc_font.width;
        region.dy = sy * vc->vc_font.height;
        region.width = width * vc->vc_font.width;
@@ -213,7 +213,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
        unsigned int bs = info->var.yres - bh;
        struct fb_fillrect region;
 
-       region.color = attr_bgcol_ec(bgshift, vc);
+       region.color = attr_bgcol_ec(bgshift, vc, info);
        region.rop = ROP_COPY;
 
        if (rw && !bottom_only) {
index 0f32f4a00b2df52844022b4bcdac074a1f48e98c..022282494d3fecee136f47d831e2dd4e534fe62d 100644 (file)
@@ -84,7 +84,7 @@
 #ifdef CONFIG_MAC
 #include <asm/macints.h>
 #endif
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
 #include <asm/machdep.h>
 #include <asm/setup.h>
 #endif
@@ -147,7 +147,7 @@ static char fontname[40];
 static int info_idx = -1;
 
 /* console rotation */
-static int rotate;
+static int initial_rotation;
 static int fbcon_has_sysfs;
 
 static const struct consw fb_con;
@@ -334,10 +334,7 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info,
        switch (depth) {
        case 1:
        {
-               int col = ~(0xfff << (max(info->var.green.length,
-                                         max(info->var.red.length,
-                                             info->var.blue.length)))) & 0xff;
-
+               int col = mono_col(info);
                /* 0 or 1 */
                int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0;
                int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col;
@@ -537,9 +534,9 @@ static int __init fb_console_setup(char *this_opt)
                if (!strncmp(options, "rotate:", 7)) {
                        options += 7;
                        if (*options)
-                               rotate = simple_strtoul(options, &options, 0);
-                       if (rotate > 3)
-                               rotate = 0;
+                               initial_rotation = simple_strtoul(options, &options, 0);
+                       if (initial_rotation > 3)
+                               initial_rotation = 0;
                }
        }
        return 1;
@@ -989,7 +986,7 @@ static const char *fbcon_startup(void)
        ops->graphics = 1;
        ops->cur_rotate = -1;
        info->fbcon_par = ops;
-       p->con_rotate = rotate;
+       p->con_rotate = initial_rotation;
        set_blitting_type(vc, info);
 
        if (info->fix.type != FB_TYPE_TEXT) {
@@ -1176,7 +1173,7 @@ static void fbcon_init(struct vc_data *vc, int init)
                con_copy_unimap(vc, svc);
 
        ops = info->fbcon_par;
-       p->con_rotate = rotate;
+       p->con_rotate = initial_rotation;
        set_blitting_type(vc, info);
 
        cols = vc->vc_cols;
@@ -2795,7 +2792,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
 {
        struct fb_info *info = registered_fb[con2fb_map[fg_console]];
        struct fbcon_ops *ops = info->fbcon_par;
-       struct display *p = &fb_display[fg_console];
+       struct display *disp = &fb_display[fg_console];
        int offset, limit, scrollback_old;
 
        if (softback_top) {
@@ -2833,7 +2830,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
                        logo_shown = FBCON_LOGO_CANSHOW;
                }
                fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
-               fbcon_redraw_softback(vc, p, lines);
+               fbcon_redraw_softback(vc, disp, lines);
                fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
                return 0;
        }
@@ -2855,9 +2852,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
 
        fbcon_cursor(vc, CM_ERASE);
 
-       offset = p->yscroll - scrollback_current;
-       limit = p->vrows;
-       switch (p->scrollmode) {
+       offset = disp->yscroll - scrollback_current;
+       limit = disp->vrows;
+       switch (disp->scrollmode) {
        case SCROLL_WRAP_MOVE:
                info->var.vmode |= FB_VMODE_YWRAP;
                break;
index 8e6ef4bc7a5c75027ae59c8b35b4c5c5acdaead0..3706307e70ed271ddc84d70f1c02ef66c9ff604e 100644 (file)
@@ -93,10 +93,6 @@ struct fbcon_ops {
        (((s) >> (fgshift)) & 0x0f)
 #define attr_bgcol(bgshift,s)    \
        (((s) >> (bgshift)) & 0x0f)
-#define        attr_bgcol_ec(bgshift,vc) \
-       ((vc) ? (((vc)->vc_video_erase_char >> (bgshift)) & 0x0f) : 0)
-#define attr_fgcol_ec(fgshift,vc) \
-       ((vc) ? (((vc)->vc_video_erase_char >> (fgshift)) & 0x0f) : 0)
 
 /* Monochrome */
 #define attr_bold(s) \
@@ -108,6 +104,49 @@ struct fbcon_ops {
 #define attr_blink(s) \
        ((s) & 0x8000)
        
+#define mono_col(info)                                                 \
+       (~(0xfff << (max((info)->var.green.length,                      \
+                        max((info)->var.red.length,                    \
+                            (info)->var.blue.length)))) & 0xff)
+
+static inline int attr_col_ec(int shift, struct vc_data *vc,
+                             struct fb_info *info, int is_fg)
+{
+       int is_mono01;
+       int col;
+       int fg;
+       int bg;
+
+       if (!vc)
+               return 0;
+
+       if (vc->vc_can_do_color)
+               return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char)
+                       : attr_bgcol(shift,vc->vc_video_erase_char);
+
+       if (!info)
+               return 0;
+
+       col = mono_col(info);
+       is_mono01 = info->fix.visual == FB_VISUAL_MONO01;
+
+       if (attr_reverse(vc->vc_video_erase_char)) {
+               fg = is_mono01 ? col : 0;
+               bg = is_mono01 ? 0 : col;
+       }
+       else {
+               fg = is_mono01 ? 0 : col;
+               bg = is_mono01 ? col : 0;
+       }
+
+       return is_fg ? fg : bg;
+}
+
+#define attr_bgcol_ec(bgshift,vc,info)         \
+       attr_col_ec(bgshift,vc,info,0);
+#define attr_fgcol_ec(fgshift,vc,info)         \
+       attr_col_ec(fgshift,vc,info,1);
+
 /* Font */
 #define REFCOUNT(fd)   (((int *)(fd))[-1])
 #define FNTSIZE(fd)    (((int *)(fd))[-2])
index 825e6d6972a72cbecb51a1194fcdaf16f0cf0a7e..bdf913ecf001de64916ede55b21c9b318743ee04 100644 (file)
@@ -84,7 +84,7 @@ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
        u32 vyres = GETVYRES(ops->p->scrollmode, info);
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = sy * vc->vc_font.height;
        region.dy = vyres - ((sx + width) * vc->vc_font.width);
        region.height = width * vc->vc_font.width;
@@ -198,7 +198,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.rop = ROP_COPY;
 
        if (rw && !bottom_only) {
index c637e6318803796e6b735b2f860227543cd0107d..a6819b9d1770cccd2690e9ee4c95f52736c27d42 100644 (file)
@@ -70,7 +70,7 @@ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
        u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = vxres - ((sy + height) * vc->vc_font.height);
        region.dy = sx *  vc->vc_font.width;
        region.height = width * vc->vc_font.width;
@@ -182,7 +182,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.rop = ROP_COPY;
 
        if (rw && !bottom_only) {
index 1473506df5d0654cba5d2bf6e5281ccc6b186870..d9b5d6eb68a73c4e9129a84679532dc191cf4693 100644 (file)
@@ -71,7 +71,7 @@ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
        u32 vyres = GETVYRES(ops->p->scrollmode, info);
        u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dy = vyres - ((sy + height) * vc->vc_font.height);
        region.dx = vxres - ((sx + width) *  vc->vc_font.width);
        region.width = width * vc->vc_font.width;
@@ -228,7 +228,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.rop = ROP_COPY;
 
        if (rw && !bottom_only) {
index 96979c37751846f9143a218401d0eb6a5ec02182..d0c03fd7087141359d3d733791bbca2020de0de0 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
 #include <asm/setup.h>
 #endif
 #include <linux/font.h>
@@ -120,7 +120,7 @@ const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
     for(i=0; i<num_fonts; i++) {
        f = fonts[i];
        c = f->pref;
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
 #ifdef CONFIG_FONT_PEARL_8x8
        if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
            c = 100;
index d981fe4d86c6b18dc5396dc99a032b5f02ca455d..0056a41e5c35c2a3d323c69845a2db895a080108 100644 (file)
@@ -40,8 +40,8 @@ static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
 
        rect.index = vc->vc_video_erase_char &
                ((vc->vc_hi_font_mask) ? 0x1ff : 0xff);
-       rect.fg = attr_fgcol_ec(fgshift, vc);
-       rect.bg = attr_bgcol_ec(bgshift, vc);
+       rect.fg = attr_fgcol_ec(fgshift, vc, info);
+       rect.bg = attr_bgcol_ec(bgshift, vc, info);
        rect.sx = sx;
        rect.sy = sy;
        rect.width = width;
index f65bcd314d54118b0b8d5fd69847fd060a352f69..6df29a62d7202552d63ced7bfc588ef8854d6c49 100644 (file)
@@ -1153,8 +1153,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
 
        /* if 512 char mode is already enabled don't re-enable it. */
        if ((set) && (ch512 != vga_512_chars)) {
-               int i;  
-               
                /* attribute controller */
                for (i = 0; i < MAX_NR_CONSOLES; i++) {
                        struct vc_data *c = vc_cons[i].d;
index a0c5d9d90d741499e5cdb6087d138337c494b3e9..0f8cfb988c901a7f45314387149a759d8b252929 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/pagemap.h>
 
 /* this is to find and return the vmalloc-ed fb pages */
-static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
-                                       unsigned long vaddr, int *type)
+static int fb_deferred_io_fault(struct vm_area_struct *vma,
+                               struct vm_fault *vmf)
 {
        unsigned long offset;
        struct page *page;
@@ -34,18 +34,17 @@ static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
        /* info->screen_base is in System RAM */
        void *screen_base = (void __force *) info->screen_base;
 
-       offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+       offset = vmf->pgoff << PAGE_SHIFT;
        if (offset >= info->fix.smem_len)
-               return NOPAGE_SIGBUS;
+               return VM_FAULT_SIGBUS;
 
        page = vmalloc_to_page(screen_base + offset);
        if (!page)
-               return NOPAGE_OOM;
+               return VM_FAULT_SIGBUS;
 
        get_page(page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return page;
+       vmf->page = page;
+       return 0;
 }
 
 int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
@@ -84,7 +83,7 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
 }
 
 static struct vm_operations_struct fb_deferred_io_vm_ops = {
-       .nopage         = fb_deferred_io_nopage,
+       .fault          = fb_deferred_io_fault,
        .page_mkwrite   = fb_deferred_io_mkwrite,
 };
 
index cdafbe14ef1fa511bf97f82efb3af88064ae9f55..a2a0618d86a54aa34ed7a45364e559bcc040636e 100644 (file)
@@ -91,6 +91,7 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
                val = comp(val >> 2, val << 2, REV_PIXELS_MASK2);
        if (bswapmask & 3)
                val = comp(val >> 4, val << 4, REV_PIXELS_MASK4);
+       return val;
 }
 
 static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
index 4ba9c08944161043fb1c9a13a3e4a0b5652dc5c7..052e180584987260a19a96a2e253b768af71f11e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
  *
  * Credits:
- * 
+ *
  * The EDID Parser is a conglomeration from the following sources:
  *
  *   1. SciTech SNAP Graphics Architecture
  *
  *   2. XFree86 4.3.0, interpret_edid.c
  *      Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
- * 
- *   3. John Fremlin <vii@users.sourceforge.net> and 
+ *
+ *   3. John Fremlin <vii@users.sourceforge.net> and
  *      Ani Joshi <ajoshi@unixbox.com>
- *  
+ *
  * Generalized Timing Formula is derived from:
  *
- *      GTF Spreadsheet by Andy Morrish (1/5/97) 
+ *      GTF Spreadsheet by Andy Morrish (1/5/97)
  *      available at http://www.vesa.org
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -36,7 +36,7 @@
 #endif
 #include "edid.h"
 
-/* 
+/*
  * EDID parser
  */
 
@@ -160,8 +160,8 @@ static int check_edid(unsigned char *edid)
        for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
                if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
                        brokendb[i].model == model) {
-                       fix = brokendb[i].fix;
-                       break;
+                       fix = brokendb[i].fix;
+                       break;
                }
        }
 
@@ -323,7 +323,7 @@ static void get_dpms_capabilities(unsigned char flags,
               (flags & DPMS_SUSPEND)    ? "yes" : "no",
               (flags & DPMS_STANDBY)    ? "yes" : "no");
 }
-       
+
 static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
 {
        int tmp;
@@ -365,7 +365,7 @@ static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
        tmp += 512;
        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;
@@ -383,7 +383,7 @@ static void calc_mode_timings(int xres, int yres, int refresh,
                              struct fb_videomode *mode)
 {
        struct fb_var_screeninfo *var;
-       
+
        var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
 
        if (var) {
@@ -451,11 +451,11 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
 
        c = block[1];
        if (c&0x80) {
-               mode[num++] = vesa_modes[9];
+               mode[num++] = vesa_modes[9];
                DPRINTK("      800x600@72Hz\n");
        }
        if (c&0x40) {
-               mode[num++] = vesa_modes[10];
+               mode[num++] = vesa_modes[10];
                DPRINTK("      800x600@75Hz\n");
        }
        if (c&0x20) {
@@ -495,7 +495,7 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
 static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
 {
        int xres, yres = 0, refresh, ratio, i;
-       
+
        xres = (block[0] + 31) * 8;
        if (xres <= 256)
                return 0;
@@ -519,7 +519,7 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
 
        DPRINTK("      %dx%d@%dHz\n", xres, yres, refresh);
        for (i = 0; i < VESA_MODEDB_SIZE; i++) {
-               if (vesa_modes[i].xres == xres && 
+               if (vesa_modes[i].xres == xres &&
                    vesa_modes[i].yres == yres &&
                    vesa_modes[i].refresh == refresh) {
                        *mode = vesa_modes[i];
@@ -536,13 +536,13 @@ static int get_dst_timing(unsigned char *block,
 {
        int j, num = 0;
 
-       for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE) 
+       for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
                num += get_std_timing(block, &mode[num]);
 
        return num;
 }
 
-static void get_detailed_timing(unsigned char *block, 
+static void get_detailed_timing(unsigned char *block,
                                struct fb_videomode *mode)
 {
        mode->xres = H_ACTIVE;
@@ -553,7 +553,7 @@ static void get_detailed_timing(unsigned char *block,
        mode->right_margin = H_SYNC_OFFSET;
        mode->left_margin = (H_ACTIVE + H_BLANKING) -
                (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
-       mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - 
+       mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
                V_SYNC_WIDTH;
        mode->lower_margin = V_SYNC_OFFSET;
        mode->hsync_len = H_SYNC_WIDTH;
@@ -597,7 +597,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
        if (mode == NULL)
                return NULL;
 
-       if (edid == NULL || !edid_checksum(edid) || 
+       if (edid == NULL || !edid_checksum(edid) ||
            !edid_check_header(edid)) {
                kfree(mode);
                return NULL;
@@ -632,7 +632,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
                if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
                        num += get_dst_timing(block + 5, &mode[num]);
        }
-       
+
        /* Yikes, EDID data is totally useless */
        if (!num) {
                kfree(mode);
@@ -686,7 +686,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
        /* estimate monitor limits based on modes supported */
        if (retval) {
                struct fb_videomode *modes, *mode;
-               int num_modes, i, hz, hscan, pixclock;
+               int num_modes, hz, hscan, pixclock;
                int vtotal, htotal;
 
                modes = fb_create_modedb(edid, &num_modes);
@@ -713,7 +713,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
                        hscan = (pixclock + htotal / 2) / htotal;
                        hscan = (hscan + 500) / 1000 * 1000;
                        hz = (hscan + vtotal / 2) / vtotal;
-                       
+
                        if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
                                specs->dclkmax = pixclock;
 
@@ -966,8 +966,8 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
        DPRINTK("========================================\n");
 }
 
-/* 
- * VESA Generalized Timing Formula (GTF) 
+/*
+ * VESA Generalized Timing Formula (GTF)
  */
 
 #define FLYBACK                     550
@@ -996,7 +996,7 @@ struct __fb_timings {
  * @hfreq: horizontal freq
  *
  * DESCRIPTION:
- * vblank = right_margin + vsync_len + left_margin 
+ * vblank = right_margin + vsync_len + left_margin
  *
  *    given: right_margin = 1 (V_FRONTPORCH)
  *           vsync_len    = 3
@@ -1010,12 +1010,12 @@ static u32 fb_get_vblank(u32 hfreq)
 {
        u32 vblank;
 
-       vblank = (hfreq * FLYBACK)/1000; 
+       vblank = (hfreq * FLYBACK)/1000;
        vblank = (vblank + 500)/1000;
        return (vblank + V_FRONTPORCH);
 }
 
-/** 
+/**
  * fb_get_hblank_by_freq - get horizontal blank time given hfreq
  * @hfreq: horizontal freq
  * @xres: horizontal resolution in pixels
@@ -1031,7 +1031,7 @@ static u32 fb_get_vblank(u32 hfreq)
  *
  * where: C = ((offset - scale factor) * blank_scale)
  *            -------------------------------------- + scale factor
- *                        256 
+ *                        256
  *        M = blank_scale * gradient
  *
  */
@@ -1039,7 +1039,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
 {
        u32 c_val, m_val, duty_cycle, hblank;
 
-       c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + 
+       c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
                 H_SCALEFACTOR) * 1000;
        m_val = (H_BLANKSCALE * H_GRADIENT)/256;
        m_val = (m_val * 1000000)/hfreq;
@@ -1048,7 +1048,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
        return (hblank);
 }
 
-/** 
+/**
  * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
  * @dclk: pixelclock in Hz
  * @xres: horizontal resolution in pixels
@@ -1061,7 +1061,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
  *
  * duty cycle = percent of htotal assigned to inactive display
  * duty cycle = C - (M * h_period)
- * 
+ *
  * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
  *                   -----------------------------------------------
  *                                    2 * M
@@ -1077,11 +1077,11 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
        h_period = 100 - C_VAL;
        h_period *= h_period;
        h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
-       h_period *=10000; 
+       h_period *= 10000;
 
        h_period = int_sqrt(h_period);
        h_period -= (100 - C_VAL) * 100;
-       h_period *= 1000; 
+       h_period *= 1000;
        h_period /= 2 * M_VAL;
 
        duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
@@ -1089,7 +1089,7 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
        hblank &= ~15;
        return (hblank);
 }
-       
+
 /**
  * fb_get_hfreq - estimate hsync
  * @vfreq: vertical refresh rate
@@ -1100,13 +1100,13 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
  *          (yres + front_port) * vfreq * 1000000
  * hfreq = -------------------------------------
  *          (1000000 - (vfreq * FLYBACK)
- * 
+ *
  */
 
 static u32 fb_get_hfreq(u32 vfreq, u32 yres)
 {
        u32 divisor, hfreq;
-       
+
        divisor = (1000000 - (vfreq * FLYBACK))/1000;
        hfreq = (yres + V_FRONTPORCH) * vfreq  * 1000;
        return (hfreq/divisor);
@@ -1117,7 +1117,7 @@ static void fb_timings_vfreq(struct __fb_timings *timings)
        timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
        timings->vblank = fb_get_vblank(timings->hfreq);
        timings->vtotal = timings->vactive + timings->vblank;
-       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 
+       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
                                                 timings->hactive);
        timings->htotal = timings->hactive + timings->hblank;
        timings->dclk = timings->htotal * timings->hfreq;
@@ -1128,7 +1128,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings)
        timings->vblank = fb_get_vblank(timings->hfreq);
        timings->vtotal = timings->vactive + timings->vblank;
        timings->vfreq = timings->hfreq/timings->vtotal;
-       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 
+       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
                                                 timings->hactive);
        timings->htotal = timings->hactive + timings->hblank;
        timings->dclk = timings->htotal * timings->hfreq;
@@ -1136,7 +1136,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings)
 
 static void fb_timings_dclk(struct __fb_timings *timings)
 {
-       timings->hblank = fb_get_hblank_by_dclk(timings->dclk, 
+       timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
                                                timings->hactive);
        timings->htotal = timings->hactive + timings->hblank;
        timings->hfreq = timings->dclk/timings->htotal;
@@ -1156,29 +1156,29 @@ static void fb_timings_dclk(struct __fb_timings *timings)
  * @info: pointer to fb_info
  *
  * DESCRIPTION:
- * Calculates video mode based on monitor specs using VESA GTF. 
- * The GTF is best for VESA GTF compliant monitors but is 
+ * Calculates video mode based on monitor specs using VESA GTF.
+ * The GTF is best for VESA GTF compliant monitors but is
  * specifically formulated to work for older monitors as well.
  *
- * If @flag==0, the function will attempt to maximize the 
+ * If @flag==0, the function will attempt to maximize the
  * refresh rate.  Otherwise, it will calculate timings based on
- * the flag and accompanying value.  
+ * the flag and accompanying value.
  *
- * If FB_IGNOREMON bit is set in @flags, monitor specs will be 
+ * If FB_IGNOREMON bit is set in @flags, monitor specs will be
  * ignored and @var will be filled with the calculated timings.
  *
  * All calculations are based on the VESA GTF Spreadsheet
  * available at VESA's public ftp (http://www.vesa.org).
- * 
+ *
  * NOTES:
  * The timings generated by the GTF will be different from VESA
  * DMT.  It might be a good idea to keep a table of standard
  * VESA modes as well.  The GTF may also not work for some displays,
  * such as, and especially, analog TV.
- *   
+ *
  * REQUIRES:
  * A valid info->monspecs, otherwise 'safe numbers' will be used.
- */ 
+ */
 int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct __fb_timings *timings;
@@ -1191,7 +1191,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
        if (!timings)
                return -ENOMEM;
 
-       /* 
+       /*
         * If monspecs are invalid, use values that are enough
         * for 640x480@60
         */
@@ -1214,7 +1214,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
 
        timings->hactive = var->xres;
        timings->vactive = var->yres;
-       if (var->vmode & FB_VMODE_INTERLACED) { 
+       if (var->vmode & FB_VMODE_INTERLACED) {
                timings->vactive /= 2;
                interlace = 2;
        }
@@ -1250,9 +1250,9 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
                break;
        default:
                err = -EINVAL;
-               
-       } 
-       
+
+       }
+
        if (err || (!(flags & FB_IGNOREMON) &&
            (timings->vfreq < vfmin || timings->vfreq > vfmax ||
             timings->hfreq < hfmin || timings->hfreq > hfmax ||
@@ -1269,7 +1269,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
                var->upper_margin = (timings->vblank * interlace)/dscan -
                        (var->vsync_len + var->lower_margin);
        }
-       
+
        kfree(timings);
        return err;
 }
@@ -1291,7 +1291,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
        return -EINVAL;
 }
 #endif /* CONFIG_FB_MODE_HELPERS */
-       
+
 /*
  * fb_validate_mode - validates var against monitor capabilities
  * @var: pointer to fb_var_screeninfo
@@ -1309,7 +1309,7 @@ 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;
 
-       /* 
+       /*
         * If monspecs are invalid, use values that are enough
         * for 640x480@60
         */
@@ -1333,10 +1333,10 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
        if (!var->pixclock)
                return -EINVAL;
        pixclock = PICOS2KHZ(var->pixclock) * 1000;
-          
-       htotal = var->xres + var->right_margin + var->hsync_len + 
+
+       htotal = var->xres + var->right_margin + var->hsync_len +
                var->left_margin;
-       vtotal = var->yres + var->lower_margin + var->vsync_len + 
+       vtotal = var->yres + var->lower_margin + var->vsync_len +
                var->upper_margin;
 
        if (var->vmode & FB_VMODE_INTERLACED)
@@ -1349,7 +1349,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
 
        vfreq = hfreq/vtotal;
 
-       return (vfreq < vfmin || vfreq > vfmax || 
+       return (vfreq < vfmin || vfreq > vfmax ||
                hfreq < hfmin || hfreq > hfmax ||
                pixclock < dclkmin || pixclock > dclkmax) ?
                -EINVAL : 0;
index 583185fd7c94b0d50241d6a9d0f49f53b72b59ec..eb6b881715387bbdbc4226ff801d4f5cc3f193ac 100644 (file)
@@ -34,7 +34,7 @@ static int fbsize;
  * we try to make it something sane - 640x480-60 is sane
  */
 
-const struct fb_videomode geode_modedb[] __initdata = {
+static const struct fb_videomode geode_modedb[] __initdata = {
        /* 640x480-60 */
        { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
          FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
index b18486ad8e17fc11fbea0d9c9e657602c10a13da..2eb4fb15908404e8926d6342b88faed3d64d180b 100644 (file)
@@ -207,7 +207,8 @@ static struct fb_ops hpfb_ops = {
 #define HPFB_FBOMSB    0x5d    /* Frame buffer offset          */
 #define HPFB_FBOLSB    0x5f
 
-static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base)
+static int __devinit hpfb_init_one(unsigned long phys_base,
+                                  unsigned long virt_base)
 {
        unsigned long fboff, fb_width, fb_height, fb_start;
 
index 1a7d7789d8772f600c6bb3100b86b50b68a45dab..1d13dd099af81236af440329cf65727b9689b6d9 100644 (file)
@@ -1476,7 +1476,7 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
        struct i810fb_par *par = info->par;
        u8 __iomem *mmio = par->mmio_start_virtual;
 
-       if (!par->dev_flags & LOCKUP)
+       if (!(par->dev_flags & LOCKUP))
                return -ENXIO;
 
        if (cursor->image.width > 64 || cursor->image.height > 64)
index b87ea21d3d78480faeca4bdc5f06d71aea4fe2b6..3a81060137a22bd29176d885a2cec1facf3c599b 100644 (file)
@@ -400,6 +400,7 @@ int __init igafb_init(void)
         info = kzalloc(size, GFP_ATOMIC);
         if (!info) {
                 printk("igafb_init: can't alloc fb_info\n");
+                pci_dev_put(pdev);
                 return -ENOMEM;
         }
 
@@ -409,12 +410,14 @@ int __init igafb_init(void)
        if ((addr = pdev->resource[0].start) == 0) {
                 printk("igafb_init: no memory start\n");
                kfree(info);
+               pci_dev_put(pdev);
                return -ENXIO;
        }
 
        if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) {
                 printk("igafb_init: can't remap %lx[2M]\n", addr);
                kfree(info);
+               pci_dev_put(pdev);
                return -ENXIO;
        }
 
@@ -449,6 +452,7 @@ int __init igafb_init(void)
                 printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start);
                iounmap((void *)info->screen_base);
                kfree(info);
+               pci_dev_put(pdev);
                return -ENXIO;
        }
 
@@ -466,6 +470,7 @@ int __init igafb_init(void)
                iounmap((void *)par->io_base);
                iounmap(info->screen_base);
                kfree(info);
+               pci_dev_put(pdev);
                return -ENOMEM;
        }
 
index 5f6fb7d2c40898ab2dfaef590dc855876942b88e..fa1fff5535654e4f6bbce1c294efd9031d16d1a2 100644 (file)
@@ -1971,7 +1971,7 @@ void intelfbhw_cursor_reset(struct intelfb_info *dinfo)
 static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
 {
        u16 tmp;
-       struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
+       struct intelfb_info *dinfo = dev_id;
 
        spin_lock(&dinfo->int_lock);
 
index 4b6a99b5be0d7ba5c720bf5f4e09d43da93897ac..5246b0402d76ce7bedd9504c460b34a36bcca9b2 100644 (file)
@@ -2066,40 +2066,49 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st
 
        switch (info->fix.accel) {
        case FB_ACCEL_NEOMAGIC_NM2070:
-               sprintf(info->fix.id, "MagicGraph 128");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128");
                break;
        case FB_ACCEL_NEOMAGIC_NM2090:
-               sprintf(info->fix.id, "MagicGraph 128V");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128V");
                break;
        case FB_ACCEL_NEOMAGIC_NM2093:
-               sprintf(info->fix.id, "MagicGraph 128ZV");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128ZV");
                break;
        case FB_ACCEL_NEOMAGIC_NM2097:
-               sprintf(info->fix.id, "MagicGraph 128ZV+");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128ZV+");
                break;
        case FB_ACCEL_NEOMAGIC_NM2160:
-               sprintf(info->fix.id, "MagicGraph 128XD");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128XD");
                break;
        case FB_ACCEL_NEOMAGIC_NM2200:
-               sprintf(info->fix.id, "MagicGraph 256AV");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256AV");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
                break;
        case FB_ACCEL_NEOMAGIC_NM2230:
-               sprintf(info->fix.id, "MagicGraph 256AV+");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256AV+");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
                break;
        case FB_ACCEL_NEOMAGIC_NM2360:
-               sprintf(info->fix.id, "MagicGraph 256ZX");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256ZX");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
                break;
        case FB_ACCEL_NEOMAGIC_NM2380:
-               sprintf(info->fix.id, "MagicGraph 256XL+");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256XL+");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
index 30e14eb1f51e60e126166fa0c94d3a3cc08741f9..74517b1b26a6d2bfd8c7c79fa018b86df2b20dc3 100644 (file)
@@ -849,9 +849,27 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var,
        if (!mode_valid && info->monspecs.modedb_len)
                return -EINVAL;
 
+       /*
+        * If we're on a flat panel, check if the mode is outside of the
+        * panel dimensions. If so, cap it and try for the next best mode
+        * before bailing out.
+        */
        if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres ||
-                                             par->fpHeight < var->yres))
-               return -EINVAL;
+                                             par->fpHeight < var->yres)) {
+               const struct fb_videomode *mode;
+
+               var->xres = par->fpWidth;
+               var->yres = par->fpHeight;
+
+               mode = fb_find_best_mode(var, &info->modelist);
+               if (!mode) {
+                       printk(KERN_ERR PFX "mode out of range of flat "
+                              "panel dimensions\n");
+                       return -EINVAL;
+               }
+
+               fb_videomode_to_var(var, mode);
+       }
 
        if (var->yres_virtual < var->yres)
                var->yres_virtual = var->yres;
index 5591dfb22b18fe2710942d3647cb374a4c0dc526..30181b593829b1e94fe6d5229965d8894c4357cd 100644 (file)
@@ -1159,6 +1159,11 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
        u32 fgx, bgx;
        const u32 *src = (const u32 *)image->data;
        u32 xres = (info->var.xres + 31) & ~31;
+       int raster_mode = 1; /* invert bits */
+
+#ifdef __LITTLE_ENDIAN
+       raster_mode |= 3 << 7; /* reverse byte order */
+#endif
 
        if (info->state != FBINFO_STATE_RUNNING)
                return;
@@ -1208,9 +1213,8 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
                pm2_WR(par, PM2R_RENDER,
                        PM2F_RENDER_RECTANGLE |
                        PM2F_INCREASE_X | PM2F_INCREASE_Y);
-               /* BitMapPackEachScanline & invert bits and byte order*/
-               /* force background */
-               pm2_WR(par, PM2R_RASTERIZER_MODE,  (1 << 9) | 1 | (3 << 7));
+               /* BitMapPackEachScanline */
+               pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9));
                pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
                pm2_WR(par, PM2R_RENDER,
                        PM2F_RENDER_RECTANGLE |
@@ -1224,8 +1228,7 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
                        PM2F_RENDER_RECTANGLE |
                        PM2F_RENDER_FASTFILL |
                        PM2F_INCREASE_X | PM2F_INCREASE_Y);
-               /* invert bits and byte order*/
-               pm2_WR(par, PM2R_RASTERIZER_MODE,  1 | (3 << 7));
+               pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode);
                pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
                pm2_WR(par, PM2R_RENDER,
                        PM2F_RENDER_RECTANGLE |
index 070659992c1841bd6fccac6f9d2abd56ec174011..5dba8cdd05173709c2365559c11d6b760a052adc 100644 (file)
@@ -1227,7 +1227,7 @@ static struct fb_ops pm3fb_ops = {
 
 /* mmio register are already mapped when this function is called */
 /* the pm3fb_fix.smem_start is also set */
-static unsigned long pm3fb_size_memory(struct pm3_par *par)
+static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par)
 {
        unsigned long   memsize = 0;
        unsigned long   tempBypass, i, temp1, temp2;
index a864438b6008bcde0d9baba19821f13fff1b6435..6515ec11c16ba250f55f6cbe6a10b6a74f7effca 100644 (file)
@@ -150,7 +150,7 @@ static int aafbcon_set_font(struct display *disp, int width, int height)
 {
        struct aafb_info *info = (struct aafb_info *)disp->fb_info;
        struct aafb_cursor *c = &info->cursor;
-       u8 fgc = ~attr_bgcol_ec(disp, disp->conp);
+       u8 fgc = ~attr_bgcol_ec(disp, disp->conp, &info->info);
 
        if (width > 64 || height > 64 || width < 0 || height < 0)
                return -EINVAL;
index 044a423a72cbe406e0a5811796b246cb788f1ec3..dc3af1c78c56ce2fff1fa32a5f8961ae727a496a 100644 (file)
@@ -57,8 +57,6 @@
 #define GPU_ALIGN_UP(x)                                _ALIGN_UP((x), 64)
 #define GPU_MAX_LINE_LENGTH                    (65536 - 64)
 
-#define PS3FB_FULL_MODE_BIT                    0x80
-
 #define GPU_INTR_STATUS_VSYNC_0                        0       /* vsync on head A */
 #define GPU_INTR_STATUS_VSYNC_1                        1       /* vsync on head B */
 #define GPU_INTR_STATUS_FLIP_0                 3       /* flip head A */
@@ -118,8 +116,6 @@ struct ps3fb_priv {
        unsigned int irq_no;
 
        u64 context_handle, memory_handle;
-       void *xdr_ea;
-       size_t xdr_size;
        struct gpu_driver_info *dinfo;
 
        u64 vblank_count;       /* frame count */
@@ -136,42 +132,19 @@ static struct ps3fb_priv ps3fb;
 struct ps3fb_par {
        u32 pseudo_palette[16];
        int mode_id, new_mode_id;
-       int res_index;
        unsigned int num_frames;        /* num of frame buffers */
        unsigned int width;
        unsigned int height;
-       unsigned long full_offset;      /* start of fullscreen DDR fb */
-       unsigned long fb_offset;        /* start of actual DDR fb */
-       unsigned long pan_offset;
+       unsigned int ddr_line_length;
+       unsigned int ddr_frame_size;
+       unsigned int xdr_frame_size;
+       unsigned int full_offset;       /* start of fullscreen DDR fb */
+       unsigned int fb_offset;         /* start of actual DDR fb */
+       unsigned int pan_offset;
 };
 
-struct ps3fb_res_table {
-       u32 xres;
-       u32 yres;
-       u32 xoff;
-       u32 yoff;
-       u32 type;
-};
-#define PS3FB_RES_FULL 1
-static const struct ps3fb_res_table ps3fb_res[] = {
-       /* res_x,y   margin_x,y  full */
-       {  720,  480,  72,  48 , 0},
-       {  720,  576,  72,  58 , 0},
-       { 1280,  720,  78,  38 , 0},
-       { 1920, 1080, 116,  58 , 0},
-       /* full mode */
-       {  720,  480,   0,   0 , PS3FB_RES_FULL},
-       {  720,  576,   0,   0 , PS3FB_RES_FULL},
-       { 1280,  720,   0,   0 , PS3FB_RES_FULL},
-       { 1920, 1080,   0,   0 , PS3FB_RES_FULL},
-       /* vesa: normally full mode */
-       { 1280,  768,   0,   0 , 0},
-       { 1280, 1024,   0,   0 , 0},
-       { 1920, 1200,   0,   0 , 0},
-       {    0,    0,   0,   0 , 0} };
-
-/* default resolution */
-#define GPU_RES_INDEX  0               /* 720 x 480 */
+
+#define FIRST_NATIVE_MODE_INDEX        10
 
 static const struct fb_videomode ps3fb_modedb[] = {
     /* 60 Hz broadcast modes (modes "1" to "5") */
@@ -211,7 +184,7 @@ static const struct fb_videomode ps3fb_modedb[] = {
         "720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5,
         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
     },    {
-        /* 1080 */
+        /* 1080i */
         "1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5,
         FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
     },    {
@@ -220,24 +193,7 @@ static const struct fb_videomode ps3fb_modedb[] = {
         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
     },
 
-    /* VESA modes (modes "11" to "13") */
-    {
-       /* WXGA */
-       "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
-       0, FB_VMODE_NONINTERLACED,
-       FB_MODE_IS_VESA
-    }, {
-       /* SXGA */
-       "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
-       FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
-       FB_MODE_IS_VESA
-    }, {
-       /* WUXGA */
-       "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
-       FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
-       FB_MODE_IS_VESA
-    },
-
+    [FIRST_NATIVE_MODE_INDEX] =
     /* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */
     {
        /* 480if */
@@ -276,12 +232,30 @@ static const struct fb_videomode ps3fb_modedb[] = {
        FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
     }, {
        /* 1080if */
-       "1080f", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
+       "1080if", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
        FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
     }, {
        /* 1080pf */
        "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5,
        FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+    },
+
+    /* VESA modes (modes "11" to "13") */
+    {
+       /* WXGA */
+       "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
+       0, FB_VMODE_NONINTERLACED,
+       FB_MODE_IS_VESA
+    }, {
+       /* SXGA */
+       "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+       FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
+       FB_MODE_IS_VESA
+    }, {
+       /* WUXGA */
+       "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
+       FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
+       FB_MODE_IS_VESA
     }
 };
 
@@ -289,110 +263,188 @@ static const struct fb_videomode ps3fb_modedb[] = {
 #define HEAD_A
 #define HEAD_B
 
-#define X_OFF(i)       (ps3fb_res[i].xoff)     /* left/right margin (pixel) */
-#define Y_OFF(i)       (ps3fb_res[i].yoff)     /* top/bottom margin (pixel) */
-#define WIDTH(i)       (ps3fb_res[i].xres)     /* width of FB */
-#define HEIGHT(i)      (ps3fb_res[i].yres)     /* height of FB */
 #define BPP            4                       /* number of bytes per pixel */
 
-/* Start of the virtual frame buffer (relative to fullscreen ) */
-#define VP_OFF(i)      ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP)
-
 
 static int ps3fb_mode;
 module_param(ps3fb_mode, int, 0);
 
 static char *mode_option __devinitdata;
 
-static int ps3fb_get_res_table(u32 xres, u32 yres, int mode)
+static int ps3fb_cmp_mode(const struct fb_videomode *vmode,
+                         const struct fb_var_screeninfo *var)
 {
-       int full_mode;
-       unsigned int i;
-       u32 x, y, f;
-
-       full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0;
-       for (i = 0;; i++) {
-               x = ps3fb_res[i].xres;
-               y = ps3fb_res[i].yres;
-               f = ps3fb_res[i].type;
-
-               if (!x) {
-                       pr_debug("ERROR: ps3fb_get_res_table()\n");
-                       return -1;
-               }
+       long xres, yres, left_margin, right_margin, upper_margin, lower_margin;
+       long dx, dy;
+
+       /* maximum values */
+       if (var->xres > vmode->xres || var->yres > vmode->yres ||
+           var->pixclock > vmode->pixclock ||
+           var->hsync_len > vmode->hsync_len ||
+           var->vsync_len > vmode->vsync_len)
+               return -1;
 
-               if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL)
-                       continue;
+       /* progressive/interlaced must match */
+       if ((var->vmode & FB_VMODE_MASK) != vmode->vmode)
+               return -1;
 
-               if (x == xres && (yres == 0 || y == yres))
-                       break;
+       /* minimum resolution */
+       xres = max(var->xres, 1U);
+       yres = max(var->yres, 1U);
+
+       /* minimum margins */
+       left_margin = max(var->left_margin, vmode->left_margin);
+       right_margin = max(var->right_margin, vmode->right_margin);
+       upper_margin = max(var->upper_margin, vmode->upper_margin);
+       lower_margin = max(var->lower_margin, vmode->lower_margin);
+
+       /* resolution + margins may not exceed native parameters */
+       dx = ((long)vmode->left_margin + (long)vmode->xres +
+             (long)vmode->right_margin) -
+            (left_margin + xres + right_margin);
+       if (dx < 0)
+               return -1;
 
-               x = x - 2 * ps3fb_res[i].xoff;
-               y = y - 2 * ps3fb_res[i].yoff;
-               if (x == xres && (yres == 0 || y == yres))
-                       break;
+       dy = ((long)vmode->upper_margin + (long)vmode->yres +
+             (long)vmode->lower_margin) -
+            (upper_margin + yres + lower_margin);
+       if (dy < 0)
+               return -1;
+
+       /* exact match */
+       if (!dx && !dy)
+               return 0;
+
+       /* resolution difference */
+       return (vmode->xres - xres) * (vmode->yres - yres);
+}
+
+static const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id)
+{
+       return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1];
+}
+
+static const struct fb_videomode *ps3fb_vmode(int id)
+{
+       u32 mode = id & PS3AV_MODE_MASK;
+
+       if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA)
+               return NULL;
+
+       if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) {
+               /* Non-fullscreen broadcast mode */
+               return &ps3fb_modedb[mode - 1];
        }
-       return i;
+
+       return ps3fb_native_vmode(mode);
 }
 
-static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
+static unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var,
                                    u32 *ddr_line_length, u32 *xdr_line_length)
 {
-       unsigned int i, mode;
-
-       for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++)
-               if (var->xres == ps3fb_modedb[i].xres &&
-                   var->yres == ps3fb_modedb[i].yres &&
-                   var->pixclock == ps3fb_modedb[i].pixclock &&
-                   var->hsync_len == ps3fb_modedb[i].hsync_len &&
-                   var->vsync_len == ps3fb_modedb[i].vsync_len &&
-                   var->left_margin == ps3fb_modedb[i].left_margin &&
-                   var->right_margin == ps3fb_modedb[i].right_margin &&
-                   var->upper_margin == ps3fb_modedb[i].upper_margin &&
-                   var->lower_margin == ps3fb_modedb[i].lower_margin &&
-                   var->sync == ps3fb_modedb[i].sync &&
-                   (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode)
-                       goto found;
-
-       pr_debug("ps3fb_find_mode: mode not found\n");
-       return 0;
+       unsigned int id, best_id;
+       int diff, best_diff;
+       const struct fb_videomode *vmode;
+       long gap;
+
+       best_id = 0;
+       best_diff = INT_MAX;
+       pr_debug("%s: wanted %u [%u] %u x %u [%u] %u\n", __func__,
+                var->left_margin, var->xres, var->right_margin,
+                var->upper_margin, var->yres, var->lower_margin);
+       for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) {
+               vmode = ps3fb_native_vmode(id);
+               diff = ps3fb_cmp_mode(vmode, var);
+               pr_debug("%s: mode %u: %u [%u] %u x %u [%u] %u: diff = %d\n",
+                        __func__, id, vmode->left_margin, vmode->xres,
+                        vmode->right_margin, vmode->upper_margin,
+                        vmode->yres, vmode->lower_margin, diff);
+               if (diff < 0)
+                       continue;
+               if (diff < best_diff) {
+                       best_id = id;
+                       if (!diff)
+                               break;
+                       best_diff = diff;
+               }
+       }
 
-found:
-       /* Cropped broadcast modes use the full line length */
-       *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP;
+       if (!best_id) {
+               pr_debug("%s: no suitable mode found\n", __func__);
+               return 0;
+       }
 
-       if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
-               *xdr_line_length = GPU_ALIGN_UP(max(var->xres,
-                                                   var->xres_virtual) * BPP);
-               if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
-                       *xdr_line_length = GPU_MAX_LINE_LENGTH;
-       } else
-               *xdr_line_length = *ddr_line_length;
+       id = best_id;
+       vmode = ps3fb_native_vmode(id);
 
-       /* Full broadcast modes have the full mode bit set */
-       mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1;
+       *ddr_line_length = vmode->xres * BPP;
 
-       pr_debug("ps3fb_find_mode: mode %u\n", mode);
+       /* minimum resolution */
+       if (!var->xres)
+               var->xres = 1;
+       if (!var->yres)
+               var->yres = 1;
 
-       return mode;
-}
+       /* minimum virtual resolution */
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
+       if (var->yres_virtual < var->yres)
+               var->yres_virtual = var->yres;
 
-static const struct fb_videomode *ps3fb_default_mode(int id)
-{
-       u32 mode = id & PS3AV_MODE_MASK;
-       u32 flags;
+       /* minimum margins */
+       if (var->left_margin < vmode->left_margin)
+               var->left_margin = vmode->left_margin;
+       if (var->right_margin < vmode->right_margin)
+               var->right_margin = vmode->right_margin;
+       if (var->upper_margin < vmode->upper_margin)
+               var->upper_margin = vmode->upper_margin;
+       if (var->lower_margin < vmode->lower_margin)
+               var->lower_margin = vmode->lower_margin;
+
+       /* extra margins */
+       gap = ((long)vmode->left_margin + (long)vmode->xres +
+              (long)vmode->right_margin) -
+             ((long)var->left_margin + (long)var->xres +
+              (long)var->right_margin);
+       if (gap > 0) {
+               var->left_margin += gap/2;
+               var->right_margin += (gap+1)/2;
+               pr_debug("%s: rounded up H to %u [%u] %u\n", __func__,
+                        var->left_margin, var->xres, var->right_margin);
+       }
 
-       if (mode < 1 || mode > 13)
-               return NULL;
+       gap = ((long)vmode->upper_margin + (long)vmode->yres +
+              (long)vmode->lower_margin) -
+             ((long)var->upper_margin + (long)var->yres +
+              (long)var->lower_margin);
+       if (gap > 0) {
+               var->upper_margin += gap/2;
+               var->lower_margin += (gap+1)/2;
+               pr_debug("%s: rounded up V to %u [%u] %u\n", __func__,
+                        var->upper_margin, var->yres, var->lower_margin);
+       }
+
+       /* fixed fields */
+       var->pixclock = vmode->pixclock;
+       var->hsync_len = vmode->hsync_len;
+       var->vsync_len = vmode->vsync_len;
+       var->sync = vmode->sync;
 
-       flags = id & ~PS3AV_MODE_MASK;
+       if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
+               *xdr_line_length = GPU_ALIGN_UP(var->xres_virtual * BPP);
+               if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
+                       *xdr_line_length = GPU_MAX_LINE_LENGTH;
+       } else
+               *xdr_line_length = *ddr_line_length;
 
-       if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
-               /* Full broadcast mode */
-               return &ps3fb_modedb[mode + 12];
+       if (vmode->sync & FB_SYNC_BROADCAST) {
+               /* Full broadcast modes have the full mode bit set */
+               if (vmode->xres == var->xres && vmode->yres == var->yres)
+                       id |= PS3AV_MODE_FULL;
        }
 
-       return &ps3fb_modedb[mode - 1];
+       pr_debug("%s: mode %u\n", __func__, id);
+       return id;
 }
 
 static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
@@ -439,8 +491,7 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
 static int ps3fb_sync(struct fb_info *info, u32 frame)
 {
        struct ps3fb_par *par = info->par;
-       int i, error = 0;
-       u32 ddr_line_length, xdr_line_length;
+       int error = 0;
        u64 ddr_base, xdr_base;
 
        if (frame > par->num_frames - 1) {
@@ -450,16 +501,13 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
                goto out;
        }
 
-       i = par->res_index;
-       xdr_line_length = info->fix.line_length;
-       ddr_line_length = ps3fb_res[i].xres * BPP;
-       xdr_base = frame * info->var.yres_virtual * xdr_line_length;
-       ddr_base = frame * ps3fb_res[i].yres * ddr_line_length;
+       xdr_base = frame * par->xdr_frame_size;
+       ddr_base = frame * par->ddr_frame_size;
 
        ps3fb_sync_image(info->device, ddr_base + par->full_offset,
                         ddr_base + par->fb_offset, xdr_base + par->pan_offset,
-                        par->width, par->height, ddr_line_length,
-                        xdr_line_length);
+                        par->width, par->height, par->ddr_line_length,
+                        info->fix.line_length);
 
 out:
        return error;
@@ -498,22 +546,11 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        u32 xdr_line_length, ddr_line_length;
        int mode;
 
-       dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres,
-               info->var.xres);
-       dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres,
-               info->var.yres);
-
-       /* FIXME For now we do exact matches only */
        mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length);
        if (!mode)
                return -EINVAL;
 
        /* Virtual screen */
-       if (var->xres_virtual < var->xres)
-               var->xres_virtual = var->xres;
-       if (var->yres_virtual < var->yres)
-               var->yres_virtual = var->yres;
-
        if (var->xres_virtual > xdr_line_length / BPP) {
                dev_dbg(info->device,
                        "Horizontal virtual screen size too large\n");
@@ -559,7 +596,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        }
 
        /* Memory limit */
-       if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) {
+       if (var->yres_virtual * xdr_line_length > info->fix.smem_len) {
                dev_dbg(info->device, "Not enough memory\n");
                return -ENOMEM;
        }
@@ -578,39 +615,38 @@ static int ps3fb_set_par(struct fb_info *info)
 {
        struct ps3fb_par *par = info->par;
        unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines;
-       int i;
-       unsigned long offset;
+       unsigned int ddr_xoff, ddr_yoff, offset;
+       const struct fb_videomode *vmode;
        u64 dst;
 
-       dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n",
-               info->var.xres, info->var.xres_virtual,
-               info->var.yres, info->var.yres_virtual, info->var.pixclock);
-
        mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length);
        if (!mode)
                return -EINVAL;
 
-       i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
-       par->res_index = i;
+       vmode = ps3fb_native_vmode(mode & PS3AV_MODE_MASK);
 
-       info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
-       info->fix.smem_len = ps3fb.xdr_size;
        info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
        info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
        info->fix.line_length = xdr_line_length;
 
-       info->screen_base = (char __iomem *)ps3fb.xdr_ea;
+       par->ddr_line_length = ddr_line_length;
+       par->ddr_frame_size = vmode->yres * ddr_line_length;
+       par->xdr_frame_size = info->var.yres_virtual * xdr_line_length;
 
-       par->num_frames = ps3fb.xdr_size /
-                         max(ps3fb_res[i].yres * ddr_line_length,
-                             info->var.yres_virtual * xdr_line_length);
+       par->num_frames = info->fix.smem_len /
+                         max(par->ddr_frame_size, par->xdr_frame_size);
 
        /* Keep the special bits we cannot set using fb_var_screeninfo */
        par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
 
        par->width = info->var.xres;
        par->height = info->var.yres;
-       offset = VP_OFF(i);
+
+       /* Start of the virtual frame buffer (relative to fullscreen) */
+       ddr_xoff = info->var.left_margin - vmode->left_margin;
+       ddr_yoff = info->var.upper_margin - vmode->upper_margin;
+       offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP;
+
        par->fb_offset = GPU_ALIGN_UP(offset);
        par->full_offset = par->fb_offset - offset;
        par->pan_offset = info->var.yoffset * xdr_line_length +
@@ -625,16 +661,16 @@ static int ps3fb_set_par(struct fb_info *info)
        }
 
        /* Clear XDR frame buffer memory */
-       memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
+       memset((void __force *)info->screen_base, 0, info->fix.smem_len);
 
        /* Clear DDR frame buffer memory */
-       lines = ps3fb_res[i].yres * par->num_frames;
+       lines = vmode->yres * par->num_frames;
        if (par->full_offset)
                lines++;
-       maxlines = ps3fb.xdr_size / ddr_line_length;
+       maxlines = info->fix.smem_len / ddr_line_length;
        for (dst = 0; lines; dst += maxlines * ddr_line_length) {
                unsigned int l = min(lines, maxlines);
-               ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
+               ps3fb_sync_image(info->device, 0, dst, 0, vmode->xres, l,
                                 ddr_line_length, ddr_line_length);
                lines -= l;
        }
@@ -797,7 +833,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
        case PS3FB_IOCTL_SETMODE:
                {
                        struct ps3fb_par *par = info->par;
-                       const struct fb_videomode *mode;
+                       const struct fb_videomode *vmode;
                        struct fb_var_screeninfo var;
 
                        if (copy_from_user(&val, argp, sizeof(val)))
@@ -810,10 +846,10 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
                        }
                        dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
                        retval = -EINVAL;
-                       mode = ps3fb_default_mode(val);
-                       if (mode) {
+                       vmode = ps3fb_vmode(val);
+                       if (vmode) {
                                var = info->var;
-                               fb_videomode_to_var(&var, mode);
+                               fb_videomode_to_var(&var, vmode);
                                acquire_console_sem();
                                info->flags |= FBINFO_MISC_USEREVENT;
                                /* Force, in case only special bits changed */
@@ -975,10 +1011,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
                        __func__, status);
                return -ENXIO;
        }
-       dev_dbg(dev,
-               "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
-               ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar,
-               virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size);
+       dev_dbg(dev, "video:%p ioif:%lx lpar:%lx size:%lx\n",
+               ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
+               ps3fb_videomemory.size);
 
        status = lv1_gpu_context_attribute(ps3fb.context_handle,
                                           L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
@@ -1055,14 +1090,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        struct fb_info *info;
        struct ps3fb_par *par;
        int retval = -ENOMEM;
-       u32 xres, yres;
        u64 ddr_lpar = 0;
        u64 lpar_dma_control = 0;
        u64 lpar_driver_info = 0;
        u64 lpar_reports = 0;
        u64 lpar_reports_size = 0;
        u64 xdr_lpar;
-       int status, res_index;
+       void *fb_start;
+       int status;
        struct task_struct *task;
        unsigned long max_ps3fb_size;
 
@@ -1080,14 +1115,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
 
        if (!ps3fb_mode)
                ps3fb_mode = ps3av_get_mode();
-       dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode);
-
-       if (ps3fb_mode > 0 &&
-           !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
-               res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
-               dev_dbg(&dev->core, "res_index:%d\n", res_index);
-       } else
-               res_index = GPU_RES_INDEX;
+       dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode);
 
        atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
        atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
@@ -1124,7 +1152,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        }
 
        /* vsync interrupt */
-       ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
+       ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
        if (!ps3fb.dinfo) {
                dev_err(&dev->core, "%s: ioremap failed\n", __func__);
                goto err_gpu_context_free;
@@ -1134,22 +1162,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        if (retval)
                goto err_iounmap_dinfo;
 
-       /* XDR frame buffer */
-       ps3fb.xdr_ea = ps3fb_videomemory.address;
-       xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea));
-
        /* Clear memory to prevent kernel info leakage into userspace */
-       memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
-
-       /*
-        * The GPU command buffer is at the start of video memory
-        * As we don't use the full command buffer, we can put the actual
-        * frame buffer at offset GPU_FB_START and save some precious XDR
-        * memory
-        */
-       ps3fb.xdr_ea += GPU_FB_START;
-       ps3fb.xdr_size = ps3fb_videomemory.size - GPU_FB_START;
+       memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
 
+       xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
        retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
        if (retval)
                goto err_free_irq;
@@ -1161,15 +1177,22 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        par = info->par;
        par->mode_id = ~ps3fb_mode;     /* != ps3fb_mode, to trigger change */
        par->new_mode_id = ps3fb_mode;
-       par->res_index = res_index;
        par->num_frames = 1;
 
-       info->screen_base = (char __iomem *)ps3fb.xdr_ea;
        info->fbops = &ps3fb_ops;
-
        info->fix = ps3fb_fix;
-       info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
-       info->fix.smem_len = ps3fb.xdr_size;
+
+       /*
+        * The GPU command buffer is at the start of video memory
+        * As we don't use the full command buffer, we can put the actual
+        * frame buffer at offset GPU_FB_START and save some precious XDR
+        * memory
+        */
+       fb_start = ps3fb_videomemory.address + GPU_FB_START;
+       info->screen_base = (char __force __iomem *)fb_start;
+       info->fix.smem_start = virt_to_abs(fb_start);
+       info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START;
+
        info->pseudo_palette = par->pseudo_palette;
        info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
                      FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
@@ -1180,7 +1203,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
 
        if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
                          ARRAY_SIZE(ps3fb_modedb),
-                         ps3fb_default_mode(par->new_mode_id), 32)) {
+                         ps3fb_vmode(par->new_mode_id), 32)) {
                retval = -EINVAL;
                goto err_fb_dealloc;
        }
@@ -1194,9 +1217,9 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
 
        dev->core.driver_data = info;
 
-       dev_info(info->device, "%s %s, using %lu KiB of video memory\n",
+       dev_info(info->device, "%s %s, using %u KiB of video memory\n",
                 dev_driver_string(info->dev), info->dev->bus_id,
-                ps3fb.xdr_size >> 10);
+                info->fix.smem_len >> 10);
 
        task = kthread_run(ps3fbd, info, DEVICE_NAME);
        if (IS_ERR(task)) {
@@ -1219,7 +1242,7 @@ err_free_irq:
        free_irq(ps3fb.irq_no, &dev->core);
        ps3_irq_plug_destroy(ps3fb.irq_no);
 err_iounmap_dinfo:
-       iounmap((u8 __iomem *)ps3fb.dinfo);
+       iounmap((u8 __force __iomem *)ps3fb.dinfo);
 err_gpu_context_free:
        lv1_gpu_context_free(ps3fb.context_handle);
 err_gpu_memory_free:
@@ -1254,7 +1277,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
                framebuffer_release(info);
                info = dev->core.driver_data = NULL;
        }
-       iounmap((u8 __iomem *)ps3fb.dinfo);
+       iounmap((u8 __force __iomem *)ps3fb.dinfo);
 
        status = lv1_gpu_context_free(ps3fb.context_handle);
        if (status)
index b3c31d9dc591bc1c8e4780e9e086ec5254834a32..71fa6edb5c477d64cd255b9fd866ec9dbe070d28 100644 (file)
@@ -110,6 +110,11 @@ static int debug   = 0;
 
 /* useful functions */
 
+static int is_s3c2412(struct s3c2410fb_info *fbi)
+{
+       return (fbi->drv_type == DRV_S3C2412);
+}
+
 /* s3c2410fb_set_lcdaddr
  *
  * initialise lcd controller address pointers
@@ -501,7 +506,7 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
 {
        unsigned long flags;
        unsigned long irqen;
-       void __iomem *regs = fbi->io;
+       void __iomem *irq_base = fbi->irq_base;
 
        local_irq_save(flags);
 
@@ -511,9 +516,9 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
                fbi->palette_ready = 1;
 
                /* enable IRQ */
-               irqen = readl(regs + S3C2410_LCDINTMSK);
+               irqen = readl(irq_base + S3C24XX_LCDINTMSK);
                irqen &= ~S3C2410_LCDINT_FRSYNC;
-               writel(irqen, regs + S3C2410_LCDINTMSK);
+               writel(irqen, irq_base + S3C24XX_LCDINTMSK);
        }
 
        local_irq_restore(flags);
@@ -594,15 +599,17 @@ static int s3c2410fb_setcolreg(unsigned regno,
 static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
 {
        struct s3c2410fb_info *fbi = info->par;
-       void __iomem *regs = fbi->io;
+       void __iomem *tpal_reg = fbi->io;
 
        dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
 
+       tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;
+
        if (blank_mode == FB_BLANK_UNBLANK)
-               writel(0x0, regs + S3C2410_TPAL);
+               writel(0x0, tpal_reg);
        else {
                dprintk("setting TPAL to output 0x000000\n");
-               writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL);
+               writel(S3C2410_TPAL_EN, tpal_reg);
        }
 
        return 0;
@@ -663,7 +670,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info)
        dma_addr_t map_dma;
        unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
 
-       dprintk("map_video_memory(fbi=%p)\n", fbi);
+       dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
 
        info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
                                                   &map_dma, GFP_KERNEL);
@@ -672,7 +679,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info)
                /* prevent initial garbage on screen */
                dprintk("map_video_memory: clear %p:%08x\n",
                        info->screen_base, map_size);
-               memset(info->screen_base, 0xf0, map_size);
+               memset(info->screen_base, 0x00, map_size);
 
                info->fix.smem_start = map_dma;
 
@@ -709,6 +716,16 @@ static int s3c2410fb_init_registers(struct fb_info *info)
        struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;
        unsigned long flags;
        void __iomem *regs = fbi->io;
+       void __iomem *tpal;
+       void __iomem *lpcsel;
+
+       if (is_s3c2412(fbi)) {
+               tpal = regs + S3C2412_TPAL;
+               lpcsel = regs + S3C2412_TCONSEL;
+       } else {
+               tpal = regs + S3C2410_TPAL;
+               lpcsel = regs + S3C2410_LPCSEL;
+       }
 
        /* Initialise LCD with values from haret */
 
@@ -724,12 +741,12 @@ static int s3c2410fb_init_registers(struct fb_info *info)
        local_irq_restore(flags);
 
        dprintk("LPCSEL    = 0x%08lx\n", mach_info->lpcsel);
-       writel(mach_info->lpcsel, regs + S3C2410_LPCSEL);
+       writel(mach_info->lpcsel, lpcsel);
 
-       dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL));
+       dprintk("replacing TPAL %08x\n", readl(tpal));
 
        /* ensure temporary palette disabled */
-       writel(0x00, regs + S3C2410_TPAL);
+       writel(0x00, tpal);
 
        return 0;
 }
@@ -763,15 +780,15 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
 static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
 {
        struct s3c2410fb_info *fbi = dev_id;
-       void __iomem *regs = fbi->io;
-       unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND);
+       void __iomem *irq_base = fbi->irq_base;
+       unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND);
 
        if (lcdirq & S3C2410_LCDINT_FRSYNC) {
                if (fbi->palette_ready)
                        s3c2410fb_write_palette(fbi);
 
-               writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND);
-               writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND);
+               writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND);
+               writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND);
        }
 
        return IRQ_HANDLED;
@@ -779,7 +796,8 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
 
 static char driver_name[] = "s3c2410fb";
 
-static int __init s3c2410fb_probe(struct platform_device *pdev)
+static int __init s3c24xxfb_probe(struct platform_device *pdev,
+                                 enum s3c_drv_type drv_type)
 {
        struct s3c2410fb_info *info;
        struct s3c2410fb_display *display;
@@ -799,6 +817,12 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       if (mach_info->default_display >= mach_info->num_displays) {
+               dev_err(&pdev->dev, "default is %d but only %d displays\n",
+                       mach_info->default_display, mach_info->num_displays);
+               return -EINVAL;
+       }
+
        display = mach_info->displays + mach_info->default_display;
 
        irq = platform_get_irq(pdev, 0);
@@ -815,6 +839,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
 
        info = fbinfo->par;
        info->dev = &pdev->dev;
+       info->drv_type = drv_type;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
@@ -838,6 +863,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
                goto release_mem;
        }
 
+       info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);
+
        dprintk("devinit\n");
 
        strcpy(fbinfo->fix.id, driver_name);
@@ -946,6 +973,16 @@ dealloc_fb:
        return ret;
 }
 
+static int __init s3c2410fb_probe(struct platform_device *pdev)
+{
+       return s3c24xxfb_probe(pdev, DRV_S3C2410);
+}
+
+static int __init s3c2412fb_probe(struct platform_device *pdev)
+{
+       return s3c24xxfb_probe(pdev, DRV_S3C2412);
+}
+
 /* s3c2410fb_stop_lcd
  *
  * shutdown the lcd controller
@@ -1047,14 +1084,31 @@ static struct platform_driver s3c2410fb_driver = {
        },
 };
 
+static struct platform_driver s3c2412fb_driver = {
+       .probe          = s3c2412fb_probe,
+       .remove         = s3c2410fb_remove,
+       .suspend        = s3c2410fb_suspend,
+       .resume         = s3c2410fb_resume,
+       .driver         = {
+               .name   = "s3c2412-lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
 int __init s3c2410fb_init(void)
 {
-       return platform_driver_register(&s3c2410fb_driver);
+       int ret = platform_driver_register(&s3c2410fb_driver);
+
+       if (ret == 0)
+               ret = platform_driver_register(&s3c2412fb_driver);;
+
+       return ret;
 }
 
 static void __exit s3c2410fb_cleanup(void)
 {
        platform_driver_unregister(&s3c2410fb_driver);
+       platform_driver_unregister(&s3c2412fb_driver);
 }
 
 module_init(s3c2410fb_init);
index 6ce5dc26c5f7c5c33eb08e452261c2db9d0273c6..dbb73b95e2efd24167c7446eaf1544ed6a297c60 100644 (file)
 #ifndef __S3C2410FB_H
 #define __S3C2410FB_H
 
+enum s3c_drv_type {
+       DRV_S3C2410,
+       DRV_S3C2412,
+};
+
 struct s3c2410fb_info {
        struct device           *dev;
        struct clk              *clk;
 
        struct resource         *mem;
        void __iomem            *io;
+       void __iomem            *irq_base;
 
+       enum s3c_drv_type       drv_type;
        struct s3c2410fb_hw     regs;
 
        unsigned int            palette_ready;
index 93ae747440cbb97b6f20d87642fbaa901655b90e..73803624c1318cd4bb82f18a5084284d924673d3 100644 (file)
@@ -427,7 +427,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
 
        monitor->feature = buffer[0x18];
 
-       if(!buffer[0x14] & 0x80) {
+       if(!(buffer[0x14] & 0x80)) {
                if(!(buffer[0x14] & 0x08)) {
                        printk(KERN_INFO
                                "sisfb: WARNING: Monitor does not support separate syncs\n");
@@ -4621,9 +4621,9 @@ sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
 
        while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
                temp = pdev->vendor;
-               pci_dev_put(pdev);
                if(temp == pcivendor) {
                        ret = 1;
+                       pci_dev_put(pdev);
                        break;
                }
        }
index 58f200c69be31378585fa34961439c584ef3a441..e83dfba7e6361af564390dcd553dcdd6a1790ee5 100644 (file)
@@ -641,6 +641,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
 {
        unsigned long control;
        void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
+       struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;
 
        control = readl(ctrl_reg);
 
@@ -657,26 +658,34 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
                sm501fb_sync_regs(fbi);
                mdelay(10);
 
-               control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
-               writel(control, ctrl_reg);
-               sm501fb_sync_regs(fbi);
-               mdelay(10);
-
-               control |= SM501_DC_PANEL_CONTROL_FPEN;
-               writel(control, ctrl_reg);
+               if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+                       control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
+                       writel(control, ctrl_reg);
+                       sm501fb_sync_regs(fbi);
+                       mdelay(10);
+               }
 
+               if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+                       control |= SM501_DC_PANEL_CONTROL_FPEN;
+                       writel(control, ctrl_reg);
+                       sm501fb_sync_regs(fbi);
+                       mdelay(10);
+               }
        } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
                /* disable panel power */
+               if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+                       control &= ~SM501_DC_PANEL_CONTROL_FPEN;
+                       writel(control, ctrl_reg);
+                       sm501fb_sync_regs(fbi);
+                       mdelay(10);
+               }
 
-               control &= ~SM501_DC_PANEL_CONTROL_FPEN;
-               writel(control, ctrl_reg);
-               sm501fb_sync_regs(fbi);
-               mdelay(10);
-
-               control &= ~SM501_DC_PANEL_CONTROL_BIAS;
-               writel(control, ctrl_reg);
-               sm501fb_sync_regs(fbi);
-               mdelay(10);
+               if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+                       control &= ~SM501_DC_PANEL_CONTROL_BIAS;
+                       writel(control, ctrl_reg);
+                       sm501fb_sync_regs(fbi);
+                       mdelay(10);
+               }
 
                control &= ~SM501_DC_PANEL_CONTROL_DATA;
                writel(control, ctrl_reg);
@@ -1267,6 +1276,7 @@ static int sm501fb_start(struct sm501fb_info *info,
 {
        struct resource *res;
        struct device *dev;
+       int k;
        int ret;
 
        info->dev = dev = &pdev->dev;
@@ -1328,6 +1338,13 @@ static int sm501fb_start(struct sm501fb_info *info,
 
        info->fbmem_len = (res->end - res->start)+1;
 
+       /* clear framebuffer memory - avoids garbage data on unused fb */
+       memset(info->fbmem, 0, info->fbmem_len);
+
+       /* clear palette ram - undefined at power on */
+       for (k = 0; k < (256 * 3); k++)
+               writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
+
        /* enable display controller */
        sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
 
@@ -1681,6 +1698,15 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
        if (par->screen.size == 0)
                return 0;
 
+       /* blank the relevant interface to ensure unit power minimised */
+       (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
+
+       /* tell console/fb driver we are suspending */
+
+       acquire_console_sem();
+       fb_set_suspend(fbi, 1);
+       release_console_sem();
+
        /* backup copies in case chip is powered down over suspend */
 
        par->store_fb = vmalloc(par->screen.size);
@@ -1700,12 +1726,6 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
 
        memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
        memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
-       /* blank the relevant interface to ensure unit power minimised */
-       (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
-
-       acquire_console_sem();
-       fb_set_suspend(fbi, 1);
-       release_console_sem();
 
        return 0;
 
index 057bdd593800c9c9f3b22fc5066ed7ba6fd20def..71e179ea5f95db581df36b0e544169b2de947436 100644 (file)
@@ -1342,7 +1342,7 @@ out_err:
 }
 
 #ifndef MODULE
-static void tdfxfb_setup(char *options)
+static void __init tdfxfb_setup(char *options)
 {
        char *this_opt;
 
index a14ef894d5716e4413affaea26cd59725b752341..be27b9c1ed72aca6832d30f3e27b6d2d20878854 100644 (file)
@@ -2003,12 +2003,12 @@ static void __devexit uvesafb_exit(void)
 
 module_exit(uvesafb_exit);
 
-static inline int param_get_scroll(char *buffer, struct kernel_param *kp)
+static int param_get_scroll(char *buffer, struct kernel_param *kp)
 {
        return 0;
 }
 
-static inline int param_set_scroll(const char *val, struct kernel_param *kp)
+static int param_set_scroll(const char *val, struct kernel_param *kp)
 {
        ypan = 0;
 
@@ -2022,11 +2022,11 @@ static inline int param_set_scroll(const char *val, struct kernel_param *kp)
        return 0;
 }
 
-#define param_check_scroll(name, p) __param_check(name, p, void);
+#define param_check_scroll(name, p) __param_check(name, p, void)
 
 module_param_named(scroll, ypan, scroll, 0);
 MODULE_PARM_DESC(scroll,
-       "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'");
+       "Scrolling mode, set to 'redraw', 'ypan', or 'ywrap'");
 module_param_named(vgapal, pmi_setpal, invbool, 0);
 MODULE_PARM_DESC(vgapal, "Set palette using VGA registers");
 module_param_named(pmipal, pmi_setpal, bool, 0);
index 1c656667b937d5ba1d4ce1fbc6d6e6de6cd5a320..2aa71eb67c2bb048f5f80c29951cf24648dfb88c 100644 (file)
@@ -651,7 +651,7 @@ static int vmlfb_check_var_locked(struct fb_var_screeninfo *var,
                return -EINVAL;
        }
 
-       pitch = __ALIGN_MASK((var->xres * var->bits_per_pixel) >> 3, 0x3F);
+       pitch = ALIGN((var->xres * var->bits_per_pixel) >> 3, 0x40);
        mem = pitch * var->yres_virtual;
        if (mem > vinfo->vram_contig_size) {
                return -ENOMEM;
@@ -785,8 +785,7 @@ static int vmlfb_set_par_locked(struct vml_info *vinfo)
        int clock;
 
        vinfo->bytes_per_pixel = var->bits_per_pixel >> 3;
-       vinfo->stride =
-           __ALIGN_MASK(var->xres_virtual * vinfo->bytes_per_pixel, 0x3F);
+       vinfo->stride = ALIGN(var->xres_virtual * vinfo->bytes_per_pixel, 0x40);
        info->fix.line_length = vinfo->stride;
 
        if (!subsys)
index 622aece1acce38153759a8b2b8bc925d6291aca6..c8a4332d1132ef465c5aa0d522787cbd255ce293 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/swap.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
+#include <linux/delay.h>
 
 struct virtio_balloon
 {
index 8236d447adf5f90ecbf054bc5fa9f54a6ada8137..c4493091c655d109dd008983183048b02c2a304e 100644 (file)
@@ -42,5 +42,15 @@ config W1_MASTER_DS1WM
          in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
          hx4700.
 
+config W1_MASTER_GPIO
+       tristate "GPIO 1-wire busmaster"
+       depends on GENERIC_GPIO
+       help
+         Say Y here if you want to communicate with your 1-wire devices using
+         GPIO pins. This driver uses the GPIO API to control the wire.
+
+         This support is also available as a module.  If so, the module
+         will be called w1-gpio.ko.
+
 endmenu
 
index 11551b328186fb23de8a9ddc71f1a13350d802dd..1420b5bbdda81f930379dfac9e776af216af7557 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_W1_MASTER_MATROX)          += matrox_w1.o
 obj-$(CONFIG_W1_MASTER_DS2490)         += ds2490.o
 obj-$(CONFIG_W1_MASTER_DS2482)         += ds2482.o
 obj-$(CONFIG_W1_MASTER_DS1WM)          += ds1wm.o
+obj-$(CONFIG_W1_MASTER_GPIO)           += w1-gpio.o
index 5747997f8d7db5c2130c5b8e648330f9daf6084b..688e435b4d9a60cb56097ee85c82ec3b662bd479 100644 (file)
@@ -361,11 +361,12 @@ static int ds1wm_probe(struct platform_device *pdev)
                goto err1;
        }
        ds1wm_data->irq = res->start;
-       ds1wm_data->active_high = (res->flags & IORESOURCE_IRQ_HIGHEDGE) ?
-               1 : 0;
+       ds1wm_data->active_high = plat->active_high;
 
-       set_irq_type(ds1wm_data->irq, ds1wm_data->active_high ?
-                       IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING);
+       if (res->flags & IORESOURCE_IRQ_HIGHEDGE)
+               set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING);
+       if (res->flags & IORESOURCE_IRQ_LOWEDGE)
+               set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING);
 
        ret = request_irq(ds1wm_data->irq, ds1wm_isr, IRQF_DISABLED,
                          "ds1wm", ds1wm_data);
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
new file mode 100644 (file)
index 0000000..9e1138a
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * w1-gpio - GPIO w1 bus master driver
+ *
+ * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/w1-gpio.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+#include <asm/gpio.h>
+
+static void w1_gpio_write_bit_dir(void *data, u8 bit)
+{
+       struct w1_gpio_platform_data *pdata = data;
+
+       if (bit)
+               gpio_direction_input(pdata->pin);
+       else
+               gpio_direction_output(pdata->pin, 0);
+}
+
+static void w1_gpio_write_bit_val(void *data, u8 bit)
+{
+       struct w1_gpio_platform_data *pdata = data;
+
+       gpio_set_value(pdata->pin, bit);
+}
+
+static u8 w1_gpio_read_bit(void *data)
+{
+       struct w1_gpio_platform_data *pdata = data;
+
+       return gpio_get_value(pdata->pin);
+}
+
+static int __init w1_gpio_probe(struct platform_device *pdev)
+{
+       struct w1_bus_master *master;
+       struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+       int err;
+
+       if (!pdata)
+               return -ENXIO;
+
+       master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL);
+       if (!master)
+               return -ENOMEM;
+
+       err = gpio_request(pdata->pin, "w1");
+       if (err)
+               goto free_master;
+
+       master->data = pdata;
+       master->read_bit = w1_gpio_read_bit;
+
+       if (pdata->is_open_drain) {
+               gpio_direction_output(pdata->pin, 1);
+               master->write_bit = w1_gpio_write_bit_val;
+       } else {
+               gpio_direction_input(pdata->pin);
+               master->write_bit = w1_gpio_write_bit_dir;
+       }
+
+       err = w1_add_master_device(master);
+       if (err)
+               goto free_gpio;
+
+       platform_set_drvdata(pdev, master);
+
+       return 0;
+
+ free_gpio:
+       gpio_free(pdata->pin);
+ free_master:
+       kfree(master);
+
+       return err;
+}
+
+static int __exit w1_gpio_remove(struct platform_device *pdev)
+{
+       struct w1_bus_master *master = platform_get_drvdata(pdev);
+       struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+
+       w1_remove_master_device(master);
+       gpio_free(pdata->pin);
+       kfree(master);
+
+       return 0;
+}
+
+static struct platform_driver w1_gpio_driver = {
+       .driver = {
+               .name   = "w1-gpio",
+               .owner  = THIS_MODULE,
+       },
+       .remove = __exit_p(w1_gpio_remove),
+};
+
+static int __init w1_gpio_init(void)
+{
+       return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe);
+}
+
+static void __exit w1_gpio_exit(void)
+{
+       platform_driver_unregister(&w1_gpio_driver);
+}
+
+module_init(w1_gpio_init);
+module_exit(w1_gpio_exit);
+
+MODULE_DESCRIPTION("GPIO w1 bus master driver");
+MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
+MODULE_LICENSE("GPL");
index 112f4ec59035424bc36b7251fcb6367c9bca7f77..fb28acaeed6c4ab01235f09b764b8d0b7e1b20b6 100644 (file)
@@ -92,6 +92,7 @@ struct w1_therm_family_converter
        int                     (*convert)(u8 rom[9]);
 };
 
+/* The return value is millidegrees Centigrade. */
 static inline int w1_DS18B20_convert_temp(u8 rom[9]);
 static inline int w1_DS18S20_convert_temp(u8 rom[9]);
 
@@ -113,7 +114,7 @@ static struct w1_therm_family_converter w1_therm_families[] = {
 static inline int w1_DS18B20_convert_temp(u8 rom[9])
 {
        s16 t = (rom[1] << 8) | rom[0];
-       t /= 16;
+       t = t*1000/16;
        return t;
 }
 
index 33e50310e9e02418763188665457b127f4ae7520..7293c9b11f9160e2b80f89e8e9c63d6bdfd6553f 100644 (file)
@@ -675,7 +675,6 @@ static void w1_slave_found(void *data, u64 rn)
        struct w1_slave *sl;
        struct list_head *ent;
        struct w1_reg_num *tmp;
-       int family_found = 0;
        struct w1_master *dev;
        u64 rn_le = cpu_to_le64(rn);
 
@@ -698,9 +697,6 @@ static void w1_slave_found(void *data, u64 rn)
                    sl->reg_num.crc == tmp->crc) {
                        set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
                        break;
-               } else if (sl->reg_num.family == tmp->family) {
-                       family_found = 1;
-                       break;
                }
 
                slave_count++;
index b364da70ff28f048dabcb7029076019eec17dc8d..dfebdbe7440e6f31f627fdd41718cf55c459a55d 100644 (file)
@@ -175,7 +175,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
        if (!wnames)
                return ERR_PTR(-ENOMEM);
 
-       for (d = dentry, i = n; i >= 0; i--, d = d->d_parent)
+       for (d = dentry, i = (n-1); i >= 0; i--, d = d->d_parent)
                wnames[i] = (char *) d->d_name.name;
 
        clone = 1;
@@ -183,7 +183,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
        while (i < n) {
                l = min(n - i, P9_MAXWELEM);
                fid = p9_client_walk(fid, l, &wnames[i], clone);
-               if (!fid) {
+               if (IS_ERR(fid)) {
                        kfree(wnames);
                        return fid;
                }
index fbb12dadba8389a77f7cfece24fc452d86732640..9b0f0222e8bbed0947f19f0baebdef0f52aabe56 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  This file contains functions assisting in mapping VFS to 9P2000
  *
- *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ *  Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -31,7 +31,6 @@
 #include <linux/idr.h>
 #include <net/9p/9p.h>
 #include <net/9p/transport.h>
-#include <net/9p/conn.h>
 #include <net/9p/client.h>
 #include "v9fs.h"
 #include "v9fs_vfs.h"
 
 enum {
        /* Options that take integer arguments */
-       Opt_debug, Opt_msize, Opt_dfltuid, Opt_dfltgid, Opt_afid,
+       Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid,
        /* String options */
        Opt_uname, Opt_remotename, Opt_trans,
        /* Options that take no arguments */
-       Opt_legacy, Opt_nodevmap,
+       Opt_nodevmap,
        /* Cache options */
        Opt_cache_loose,
        /* Access options */
@@ -58,14 +57,11 @@ enum {
 
 static match_table_t tokens = {
        {Opt_debug, "debug=%x"},
-       {Opt_msize, "msize=%u"},
        {Opt_dfltuid, "dfltuid=%u"},
        {Opt_dfltgid, "dfltgid=%u"},
        {Opt_afid, "afid=%u"},
        {Opt_uname, "uname=%s"},
        {Opt_remotename, "aname=%s"},
-       {Opt_trans, "trans=%s"},
-       {Opt_legacy, "noextend"},
        {Opt_nodevmap, "nodevmap"},
        {Opt_cache_loose, "cache=loose"},
        {Opt_cache_loose, "loose"},
@@ -85,16 +81,14 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
        char *options;
        substring_t args[MAX_OPT_ARGS];
        char *p;
-       int option;
-       int ret;
+       int option = 0;
        char *s, *e;
+       int ret;
 
        /* setup defaults */
-       v9ses->maxdata = 8192;
        v9ses->afid = ~0;
        v9ses->debug = 0;
        v9ses->cache = 0;
-       v9ses->trans = v9fs_default_trans();
 
        if (!v9ses->options)
                return;
@@ -106,7 +100,8 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
                        continue;
                token = match_token(p, tokens, args);
                if (token < Opt_uname) {
-                       if ((ret = match_int(&args[0], &option)) < 0) {
+                       ret = match_int(&args[0], &option);
+                       if (ret < 0) {
                                P9_DPRINTK(P9_DEBUG_ERROR,
                                        "integer field, but no integer?\n");
                                continue;
@@ -119,9 +114,7 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
                        p9_debug_level = option;
 #endif
                        break;
-               case Opt_msize:
-                       v9ses->maxdata = option;
-                       break;
+
                case Opt_dfltuid:
                        v9ses->dfltuid = option;
                        break;
@@ -131,18 +124,12 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
                case Opt_afid:
                        v9ses->afid = option;
                        break;
-               case Opt_trans:
-                       v9ses->trans = v9fs_match_trans(&args[0]);
-                       break;
                case Opt_uname:
                        match_strcpy(v9ses->uname, &args[0]);
                        break;
                case Opt_remotename:
                        match_strcpy(v9ses->aname, &args[0]);
                        break;
-               case Opt_legacy:
-                       v9ses->flags &= ~V9FS_EXTENDED;
-                       break;
                case Opt_nodevmap:
                        v9ses->nodev = 1;
                        break;
@@ -185,7 +172,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
                  const char *dev_name, char *data)
 {
        int retval = -EINVAL;
-       struct p9_trans *trans = NULL;
        struct p9_fid *fid;
 
        v9ses->uname = __getname();
@@ -207,24 +193,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
        v9ses->options = kstrdup(data, GFP_KERNEL);
        v9fs_parse_options(v9ses);
 
-       if (v9ses->trans == NULL) {
-               retval = -EPROTONOSUPPORT;
-               P9_DPRINTK(P9_DEBUG_ERROR,
-                               "No transport defined or default transport\n");
-               goto error;
-       }
-
-       trans = v9ses->trans->create(dev_name, v9ses->options);
-       if (IS_ERR(trans)) {
-               retval = PTR_ERR(trans);
-               trans = NULL;
-               goto error;
-       }
-       if ((v9ses->maxdata+P9_IOHDRSZ) > v9ses->trans->maxsize)
-               v9ses->maxdata = v9ses->trans->maxsize-P9_IOHDRSZ;
-
-       v9ses->clnt = p9_client_create(trans, v9ses->maxdata+P9_IOHDRSZ,
-               v9fs_extended(v9ses));
+       v9ses->clnt = p9_client_create(dev_name, v9ses->options);
 
        if (IS_ERR(v9ses->clnt)) {
                retval = PTR_ERR(v9ses->clnt);
@@ -236,6 +205,8 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
        if (!v9ses->clnt->dotu)
                v9ses->flags &= ~V9FS_EXTENDED;
 
+       v9ses->maxdata = v9ses->clnt->msize;
+
        /* for legacy mode, fall back to V9FS_ACCESS_ANY */
        if (!v9fs_extended(v9ses) &&
                ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
index db4b4193f2e258ba77e9341f2e0fb04a72b00fcd..7d3a1018db5215ec9a410b2d789b1ea5d3e8aab5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * V9FS definitions.
  *
- *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ *  Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,6 @@
 
 struct v9fs_session_info {
        /* options */
-       unsigned int maxdata;
        unsigned char flags;    /* session flags */
        unsigned char nodev;    /* set to 1 if no disable device mapping */
        unsigned short debug;   /* debug level */
@@ -38,10 +37,10 @@ struct v9fs_session_info {
        char *options;          /* copy of mount options */
        char *uname;            /* user name to mount as */
        char *aname;            /* name of remote hierarchy being mounted */
+       unsigned int maxdata;   /* max data for client interface */
        unsigned int dfltuid;   /* default uid/muid for legacy support */
        unsigned int dfltgid;   /* default gid for legacy support */
        u32 uid;                /* if ACCESS_SINGLE, the uid that has access */
-       struct p9_trans_module *trans; /* 9p transport */
        struct p9_client *clnt; /* 9p client */
        struct dentry *debugfs_dir;
 };
index ba4b1caa9c43a7491bcef73b8e4585057ea3c57f..a616fff8906d8e803c928981a8cb346f46db7d76 100644 (file)
@@ -184,7 +184,7 @@ static const struct file_operations v9fs_cached_file_operations = {
        .open = v9fs_file_open,
        .release = v9fs_dir_release,
        .lock = v9fs_file_lock,
-       .mmap = generic_file_mmap,
+       .mmap = generic_file_readonly_mmap,
 };
 
 const struct file_operations v9fs_file_operations = {
@@ -194,5 +194,5 @@ const struct file_operations v9fs_file_operations = {
        .open = v9fs_file_open,
        .release = v9fs_dir_release,
        .lock = v9fs_file_lock,
-       .mmap = generic_file_mmap,
+       .mmap = generic_file_readonly_mmap,
 };
index 23581bcb599b2f7d6031644de612742512e218e3..6a28842052eac1ccf3c600817b3722c344036e7d 100644 (file)
@@ -77,6 +77,8 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
                        res |= P9_DMSETUID;
                if ((mode & S_ISGID) == S_ISGID)
                        res |= P9_DMSETGID;
+               if ((mode & S_ISVTX) == S_ISVTX)
+                       res |= P9_DMSETVTX;
                if ((mode & P9_DMLINK))
                        res |= P9_DMLINK;
        }
@@ -119,6 +121,9 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
 
                if ((mode & P9_DMSETGID) == P9_DMSETGID)
                        res |= S_ISGID;
+
+               if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
+                       res |= S_ISVTX;
        }
 
        return res;
@@ -568,7 +573,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
        v9ses = v9fs_inode2v9ses(dir);
        dfid = v9fs_fid_lookup(dentry->d_parent);
        if (IS_ERR(dfid))
-               return ERR_PTR(PTR_ERR(dfid));
+               return ERR_CAST(dfid);
 
        name = (char *) dentry->d_name.name;
        fid = p9_client_walk(dfid, 1, &name, 1);
index ea5b359476234452070e5ba64f44eb404c4f2107..3bf6ace1720c6230a1b44f884685c8f383541cdd 100644 (file)
@@ -463,40 +463,18 @@ config OCFS2_DEBUG_FS
          this option for debugging only as it is likely to decrease
          performance of the filesystem.
 
-config MINIX_FS
-       tristate "Minix fs support"
-       help
-         Minix is a simple operating system used in many classes about OS's.
-         The minix file system (method to organize files on a hard disk
-         partition or a floppy disk) was the original file system for Linux,
-         but has been superseded by the second extended file system ext2fs.
-         You don't want to use the minix file system on your hard disk
-         because of certain built-in restrictions, but it is sometimes found
-         on older Linux floppy disks.  This option will enlarge your kernel
-         by about 28 KB. If unsure, say N.
-
-         To compile this file system support as a module, choose M here: the
-         module will be called minix.  Note that the file system of your root
-         partition (the one containing the directory /) cannot be compiled as
-         a module.
-
-config ROMFS_FS
-       tristate "ROM file system support"
-       ---help---
-         This is a very small read-only file system mainly intended for
-         initial ram disks of installation disks, but it could be used for
-         other read-only media as well.  Read
-         <file:Documentation/filesystems/romfs.txt> for details.
-
-         To compile this file system support as a module, choose M here: the
-         module will be called romfs.  Note that the file system of your
-         root partition (the one containing the directory /) cannot be a
-         module.
+endif # BLOCK
 
-         If you don't know whether you need it, then you don't need it:
-         answer N.
+config DNOTIFY
+       bool "Dnotify support"
+       default y
+       help
+         Dnotify is a directory-based per-fd file change notification system
+         that uses signals to communicate events to user-space.  There exist
+         superior alternatives, but some applications may still rely on
+         dnotify.
 
-endif
+         If unsure, say Y.
 
 config INOTIFY
        bool "Inotify file change notification support"
@@ -577,17 +555,6 @@ config QUOTACTL
        depends on XFS_QUOTA || QUOTA
        default y
 
-config DNOTIFY
-       bool "Dnotify support"
-       default y
-       help
-         Dnotify is a directory-based per-fd file change notification system
-         that uses signals to communicate events to user-space.  There exist
-         superior alternatives, but some applications may still rely on
-         dnotify.
-
-         If unsure, say Y.
-
 config AUTOFS_FS
        tristate "Kernel automounter support"
        help
@@ -713,7 +680,7 @@ config UDF_NLS
        depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y)
 
 endmenu
-endif
+endif # BLOCK
 
 if BLOCK
 menu "DOS/FAT/NT Filesystems"
@@ -896,7 +863,7 @@ config NTFS_RW
          It is perfectly safe to say N here.
 
 endmenu
-endif
+endif # BLOCK
 
 menu "Pseudo filesystems"
 
@@ -1417,6 +1384,24 @@ config VXFS_FS
          To compile this as a module, choose M here: the module will be
          called freevxfs.  If unsure, say N.
 
+config MINIX_FS
+       tristate "Minix file system support"
+       depends on BLOCK
+       help
+         Minix is a simple operating system used in many classes about OS's.
+         The minix file system (method to organize files on a hard disk
+         partition or a floppy disk) was the original file system for Linux,
+         but has been superseded by the second extended file system ext2fs.
+         You don't want to use the minix file system on your hard disk
+         because of certain built-in restrictions, but it is sometimes found
+         on older Linux floppy disks.  This option will enlarge your kernel
+         by about 28 KB. If unsure, say N.
+
+         To compile this file system support as a module, choose M here: the
+         module will be called minix.  Note that the file system of your root
+         partition (the one containing the directory /) cannot be compiled as
+         a module.
+
 
 config HPFS_FS
        tristate "OS/2 HPFS file system support"
@@ -1434,7 +1419,6 @@ config HPFS_FS
          module will be called hpfs.  If unsure, say N.
 
 
-
 config QNX4FS_FS
        tristate "QNX4 file system support (read only)"
        depends on BLOCK
@@ -1461,6 +1445,22 @@ config QNX4FS_RW
          It's currently broken, so for now:
          answer N.
 
+config ROMFS_FS
+       tristate "ROM file system support"
+       depends on BLOCK
+       ---help---
+         This is a very small read-only file system mainly intended for
+         initial ram disks of installation disks, but it could be used for
+         other read-only media as well.  Read
+         <file:Documentation/filesystems/romfs.txt> for details.
+
+         To compile this file system support as a module, choose M here: the
+         module will be called romfs.  Note that the file system of your
+         root partition (the one containing the directory /) cannot be a
+         module.
+
+         If you don't know whether you need it, then you don't need it:
+         answer N.
 
 
 config SYSV_FS
@@ -1501,7 +1501,6 @@ config SYSV_FS
          If you haven't heard about all of this before, it's safe to say N.
 
 
-
 config UFS_FS
        tristate "UFS file system support (read only)"
        depends on BLOCK
index 232c694936836f123cecb5f5ab670ffed2d69657..d5bd497ab9cbd5154ade0781ed3bffbe3d83aeb7 100644 (file)
@@ -174,7 +174,8 @@ extern void                  affs_put_inode(struct inode *inode);
 extern void                     affs_drop_inode(struct inode *inode);
 extern void                     affs_delete_inode(struct inode *inode);
 extern void                     affs_clear_inode(struct inode *inode);
-extern void                     affs_read_inode(struct inode *inode);
+extern struct inode            *affs_iget(struct super_block *sb,
+                                       unsigned long ino);
 extern int                      affs_write_inode(struct inode *inode, int);
 extern int                      affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type);
 
index f4de4b98004fa1f9f08cbe2c6310eb805aaafd1d..805573005de66614cec77f00f83593c61fa1f027 100644 (file)
@@ -170,9 +170,11 @@ affs_remove_link(struct dentry *dentry)
                if (!link_bh)
                        goto done;
 
-               dir = iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
-               if (!dir)
+               dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
+               if (IS_ERR(dir)) {
+                       retval = PTR_ERR(dir);
                        goto done;
+               }
 
                affs_lock_dir(dir);
                affs_fix_dcache(dentry, link_ino);
index 4609a6c13fe917552b6121a5b964767e8ba76800..27fe6cbe43ae84bc1582f8e86131cebb1566eb1e 100644 (file)
 extern const struct inode_operations affs_symlink_inode_operations;
 extern struct timezone sys_tz;
 
-void
-affs_read_inode(struct inode *inode)
+struct inode *affs_iget(struct super_block *sb, unsigned long ino)
 {
-       struct super_block      *sb = inode->i_sb;
        struct affs_sb_info     *sbi = AFFS_SB(sb);
        struct buffer_head      *bh;
        struct affs_head        *head;
        struct affs_tail        *tail;
+       struct inode            *inode;
        u32                      block;
        u32                      size;
        u32                      prot;
        u16                      id;
 
-       pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       pr_debug("AFFS: affs_iget(%lu)\n", inode->i_ino);
 
        block = inode->i_ino;
        bh = affs_bread(sb, block);
@@ -154,12 +159,13 @@ affs_read_inode(struct inode *inode)
                         sys_tz.tz_minuteswest * 60;
        inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0;
        affs_brelse(bh);
-       return;
+       unlock_new_inode(inode);
+       return inode;
 
 bad_inode:
-       make_bad_inode(inode);
        affs_brelse(bh);
-       return;
+       iget_failed(inode);
+       return ERR_PTR(-EIO);
 }
 
 int
index a42143ca01698e1ba64769d5d9eb1bc0aa095320..2218f1ee71ce1c2cc146ccd876d614c78fce94cd 100644 (file)
@@ -208,9 +208,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
        affs_lock_dir(dir);
        bh = affs_find_entry(dir, dentry);
        affs_unlock_dir(dir);
-       if (IS_ERR(bh)) {
-               return ERR_PTR(PTR_ERR(bh));
-       }
+       if (IS_ERR(bh))
+               return ERR_CAST(bh);
        if (bh) {
                u32 ino = bh->b_blocknr;
 
@@ -223,10 +222,9 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
                        ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
                }
                affs_brelse(bh);
-               inode = iget(sb, ino);
-               if (!inode) {
-                       return ERR_PTR(-EACCES);
-               }
+               inode = affs_iget(sb, ino);
+               if (IS_ERR(inode))
+                       return ERR_PTR(PTR_ERR(inode));
        }
        dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
        d_add(dentry, inode);
index b53e5d0ec65c4b3fd52417dab5c85cdd176ebb76..3c45d49c0d26046780c79e9d15da0a1e39550f68 100644 (file)
@@ -113,7 +113,6 @@ static void destroy_inodecache(void)
 static const struct super_operations affs_sops = {
        .alloc_inode    = affs_alloc_inode,
        .destroy_inode  = affs_destroy_inode,
-       .read_inode     = affs_read_inode,
        .write_inode    = affs_write_inode,
        .put_inode      = affs_put_inode,
        .drop_inode     = affs_drop_inode,
@@ -271,6 +270,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
        unsigned long            mount_flags;
        int                      tmp_flags;     /* fix remount prototype... */
        u8                       sig[4];
+       int                      ret = -EINVAL;
 
        pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
 
@@ -444,7 +444,12 @@ got_root:
 
        /* set up enough so that it can read an inode */
 
-       root_inode = iget(sb, root_block);
+       root_inode = affs_iget(sb, root_block);
+       if (IS_ERR(root_inode)) {
+               ret = PTR_ERR(root_inode);
+               goto out_error_noinode;
+       }
+
        sb->s_root = d_alloc_root(root_inode);
        if (!sb->s_root) {
                printk(KERN_ERR "AFFS: Get root inode failed\n");
@@ -461,12 +466,13 @@ got_root:
 out_error:
        if (root_inode)
                iput(root_inode);
+out_error_noinode:
        kfree(sbi->s_bitmap);
        affs_brelse(root_bh);
        kfree(sbi->s_prefix);
        kfree(sbi);
        sb->s_fs_info = NULL;
-       return -EINVAL;
+       return ret;
 }
 
 static int
index 0cc3597c11971380716d10083eee9fa7660f82dd..b58af8f18bc4d36a849e7f314b9c809834a96bae 100644 (file)
@@ -512,7 +512,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
        key = afs_request_key(vnode->volume->cell);
        if (IS_ERR(key)) {
                _leave(" = %ld [key]", PTR_ERR(key));
-               return ERR_PTR(PTR_ERR(key));
+               return ERR_CAST(key);
        }
 
        ret = afs_validate(vnode, key);
@@ -540,7 +540,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
        key_put(key);
        if (IS_ERR(inode)) {
                _leave(" = %ld", PTR_ERR(inode));
-               return ERR_PTR(PTR_ERR(inode));
+               return ERR_CAST(inode);
        }
 
        dentry->d_op = &afs_fs_dentry_operations;
index 84750c8e9f95be1b07ba30ed7ab4778cf1ae9599..08db82e1343a1555fcc911fb4d42954db3fad1a0 100644 (file)
@@ -196,10 +196,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
 
        /* failure */
 bad_inode:
-       make_bad_inode(inode);
-       unlock_new_inode(inode);
-       iput(inode);
-
+       iget_failed(inode);
        _leave(" = %d [bad]", ret);
        return ERR_PTR(ret);
 }
index 566fe712c68297c63c5a7fea80eedc83402a937d..9446a1fd108a35452579df735f4877f6ad992a6f 100644 (file)
@@ -95,7 +95,7 @@ static struct afs_vnode *afs_get_auth_inode(struct afs_vnode *vnode,
                auth_inode = afs_iget(vnode->vfs_inode.i_sb, key,
                                      &vnode->status.parent, NULL, NULL);
                if (IS_ERR(auth_inode))
-                       return ERR_PTR(PTR_ERR(auth_inode));
+                       return ERR_CAST(auth_inode);
        }
 
        auth_vnode = AFS_FS_I(auth_inode);
index 8b4cca3c4705c7b880d8ded266160a84c74c0cbf..901a3e67ec4578665812eebf07b40a7a8ede2632 100644 (file)
@@ -150,6 +150,7 @@ extern const struct file_operations autofs_root_operations;
 
 int autofs_fill_super(struct super_block *, void *, int);
 void autofs_kill_sb(struct super_block *sb);
+struct inode *autofs_iget(struct super_block *, unsigned long);
 
 /* Queue management functions */
 
index 45f5992a0957173bc0c7e744028ef40e5743aa8e..708bdb89fea14782c625e14c04e63902003b442b 100644 (file)
@@ -52,10 +52,7 @@ out_kill_sb:
        kill_anon_super(sb);
 }
 
-static void autofs_read_inode(struct inode *inode);
-
 static const struct super_operations autofs_sops = {
-       .read_inode     = autofs_read_inode,
        .statfs         = simple_statfs,
 };
 
@@ -164,7 +161,9 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
        s->s_time_gran = 1;
        sbi->sb = s;
 
-       root_inode = iget(s, AUTOFS_ROOT_INO);
+       root_inode = autofs_iget(s, AUTOFS_ROOT_INO);
+       if (IS_ERR(root_inode))
+               goto fail_free;
        root = d_alloc_root(root_inode);
        pipe = NULL;
 
@@ -230,11 +229,17 @@ fail_unlock:
        return -EINVAL;
 }
 
-static void autofs_read_inode(struct inode *inode)
+struct inode *autofs_iget(struct super_block *sb, unsigned long ino)
 {
-       ino_t ino = inode->i_ino;
        unsigned int n;
-       struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);
+       struct autofs_sb_info *sbi = autofs_sbi(sb);
+       struct inode *inode;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
 
        /* Initialize to the default case (stub directory) */
 
@@ -250,7 +255,7 @@ static void autofs_read_inode(struct inode *inode)
                inode->i_op = &autofs_root_inode_operations;
                inode->i_fop = &autofs_root_operations;
                inode->i_uid = inode->i_gid = 0; /* Changed in read_super */
-               return;
+               goto done;
        } 
        
        inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
@@ -263,7 +268,7 @@ static void autofs_read_inode(struct inode *inode)
                n = ino - AUTOFS_FIRST_SYMLINK;
                if (n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) {
                        printk("autofs: Looking for bad symlink inode %u\n", (unsigned int) ino);
-                       return;
+                       goto done;
                }
                
                inode->i_op = &autofs_symlink_inode_operations;
@@ -275,4 +280,8 @@ static void autofs_read_inode(struct inode *inode)
                inode->i_size = sl->len;
                inode->i_nlink = 1;
        }
+
+done:
+       unlock_new_inode(inode);
+       return inode;
 }
index 5efff3c0d886985351bbe1588da8245992974525..8aacade56956ec650daaa537e76370724277b765 100644 (file)
@@ -114,8 +114,8 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
        dentry->d_time = (unsigned long) ent;
        
        if (!dentry->d_inode) {
-               inode = iget(sb, ent->ino);
-               if (!inode) {
+               inode = autofs_iget(sb, ent->ino);
+               if (IS_ERR(inode)) {
                        /* Failed, but leave pending for next time */
                        return 1;
                }
@@ -274,6 +274,7 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
        unsigned int n;
        int slsize;
        struct autofs_symlink *sl;
+       struct inode *inode;
 
        DPRINTK(("autofs_root_symlink: %s <- ", symname));
        autofs_say(dentry->d_name.name,dentry->d_name.len);
@@ -331,7 +332,12 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
        ent->dentry = NULL;     /* We don't keep the dentry for symlinks */
 
        autofs_hash_insert(dh,ent);
-       d_instantiate(dentry, iget(dir->i_sb,ent->ino));
+
+       inode = autofs_iget(dir->i_sb, ent->ino);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       d_instantiate(dentry, inode);
        unlock_kernel();
        return 0;
 }
@@ -428,6 +434,7 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
        struct autofs_dirhash *dh = &sbi->dirhash;
        struct autofs_dir_ent *ent;
+       struct inode *inode;
        ino_t ino;
 
        lock_kernel();
@@ -469,7 +476,14 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        autofs_hash_insert(dh,ent);
 
        inc_nlink(dir);
-       d_instantiate(dentry, iget(dir->i_sb,ino));
+
+       inode = autofs_iget(dir->i_sb, ino);
+       if (IS_ERR(inode)) {
+               drop_nlink(dir);
+               return PTR_ERR(inode);
+       }
+
+       d_instantiate(dentry, inode);
        unlock_kernel();
 
        return 0;
index 521ff7caadbd687ada5ed347edc696d70168392f..f1c2ea8342f514c974539dd5a676b650efbf6e5f 100644 (file)
@@ -359,3 +359,17 @@ int is_bad_inode(struct inode *inode)
 }
 
 EXPORT_SYMBOL(is_bad_inode);
+
+/**
+ * iget_failed - Mark an under-construction inode as dead and release it
+ * @inode: The inode to discard
+ *
+ * Mark an under-construction inode as dead and release it.
+ */
+void iget_failed(struct inode *inode)
+{
+       make_bad_inode(inode);
+       unlock_new_inode(inode);
+       iput(inode);
+}
+EXPORT_SYMBOL(iget_failed);
index b28a20e61b8061f294ea24d0037f183550fa1e7d..403fe661c14474a49636394a4e74505e1ec7e142 100644 (file)
@@ -35,7 +35,7 @@ static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 static int befs_readpage(struct file *file, struct page *page);
 static sector_t befs_bmap(struct address_space *mapping, sector_t block);
 static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *);
-static void befs_read_inode(struct inode *ino);
+static struct inode *befs_iget(struct super_block *, unsigned long);
 static struct inode *befs_alloc_inode(struct super_block *sb);
 static void befs_destroy_inode(struct inode *inode);
 static int befs_init_inodecache(void);
@@ -52,7 +52,6 @@ static int befs_statfs(struct dentry *, struct kstatfs *);
 static int parse_options(char *, befs_mount_options *);
 
 static const struct super_operations befs_sops = {
-       .read_inode     = befs_read_inode,      /* initialize & read inode */
        .alloc_inode    = befs_alloc_inode,     /* allocate a new inode */
        .destroy_inode  = befs_destroy_inode, /* deallocate an inode */
        .put_super      = befs_put_super,       /* uninit super */
@@ -198,9 +197,9 @@ befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
                return ERR_PTR(-ENODATA);
        }
 
-       inode = iget(dir->i_sb, (ino_t) offset);
-       if (!inode)
-               return ERR_PTR(-EACCES);
+       inode = befs_iget(dir->i_sb, (ino_t) offset);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
 
        d_add(dentry, inode);
 
@@ -296,17 +295,23 @@ static void init_once(struct kmem_cache *cachep, void *foo)
        inode_init_once(&bi->vfs_inode);
 }
 
-static void
-befs_read_inode(struct inode *inode)
+static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
 {
        struct buffer_head *bh = NULL;
        befs_inode *raw_inode = NULL;
 
-       struct super_block *sb = inode->i_sb;
        befs_sb_info *befs_sb = BEFS_SB(sb);
        befs_inode_info *befs_ino = NULL;
+       struct inode *inode;
+       long ret = -EIO;
 
-       befs_debug(sb, "---> befs_read_inode() " "inode = %lu", inode->i_ino);
+       befs_debug(sb, "---> befs_read_inode() " "inode = %lu", ino);
+
+       inode = iget_locked(sb, ino);
+       if (IS_ERR(inode))
+               return inode;
+       if (!(inode->i_state & I_NEW))
+               return inode;
 
        befs_ino = BEFS_I(inode);
 
@@ -402,15 +407,16 @@ befs_read_inode(struct inode *inode)
 
        brelse(bh);
        befs_debug(sb, "<--- befs_read_inode()");
-       return;
+       unlock_new_inode(inode);
+       return inode;
 
       unacquire_bh:
        brelse(bh);
 
       unacquire_none:
-       make_bad_inode(inode);
+       iget_failed(inode);
        befs_debug(sb, "<--- befs_read_inode() - Bad inode");
-       return;
+       return ERR_PTR(ret);
 }
 
 /* Initialize the inode cache. Called at fs setup.
@@ -752,6 +758,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
        befs_sb_info *befs_sb;
        befs_super_block *disk_sb;
        struct inode *root;
+       long ret = -EINVAL;
 
        const unsigned long sb_block = 0;
        const off_t x86_sb_off = 512;
@@ -833,7 +840,11 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
        /* Set real blocksize of fs */
        sb_set_blocksize(sb, (ulong) befs_sb->block_size);
        sb->s_op = (struct super_operations *) &befs_sops;
-       root = iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
+       root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
+       if (IS_ERR(root)) {
+               ret = PTR_ERR(root);
+               goto unacquire_priv_sbp;
+       }
        sb->s_root = d_alloc_root(root);
        if (!sb->s_root) {
                iput(root);
@@ -868,7 +879,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
 
       unacquire_none:
        sb->s_fs_info = NULL;
-       return -EINVAL;
+       return ret;
 }
 
 static int
index ac7a8b1d6c3ab5f749305c4c38fec63289791b19..71faf4d2390824ac2f0e001c32bb24c126f7f653 100644 (file)
@@ -44,6 +44,8 @@ static inline struct bfs_inode_info *BFS_I(struct inode *inode)
 #define printf(format, args...) \
        printk(KERN_ERR "BFS-fs: %s(): " format, __FUNCTION__, ## args)
 
+/* inode.c */
+extern struct inode *bfs_iget(struct super_block *sb, unsigned long ino);
 
 /* file.c */
 extern const struct inode_operations bfs_file_inops;
index 1fd056d0fc3dc3029f36bb5a23b38ff71a320750..034950cb3cbebde650e4e4544ee0428e765ed2b2 100644 (file)
@@ -148,10 +148,10 @@ static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry,
        if (bh) {
                unsigned long ino = (unsigned long)le16_to_cpu(de->ino);
                brelse(bh);
-               inode = iget(dir->i_sb, ino);
-               if (!inode) {
+               inode = bfs_iget(dir->i_sb, ino);
+               if (IS_ERR(inode)) {
                        unlock_kernel();
-                       return ERR_PTR(-EACCES);
+                       return ERR_CAST(inode);
                }
        }
        unlock_kernel();
index a64a71d444f50f5d2e0731f375c9994551780743..8db623838b50c78c819b70ec59e813ac13497277 100644 (file)
@@ -32,17 +32,22 @@ MODULE_LICENSE("GPL");
 
 void dump_imap(const char *prefix, struct super_block *s);
 
-static void bfs_read_inode(struct inode *inode)
+struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
 {
-       unsigned long ino = inode->i_ino;
        struct bfs_inode *di;
+       struct inode *inode;
        struct buffer_head *bh;
        int block, off;
 
+       inode = iget_locked(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
        if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {
                printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino);
-               make_bad_inode(inode);
-               return;
+               goto error;
        }
 
        block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
@@ -50,8 +55,7 @@ static void bfs_read_inode(struct inode *inode)
        if (!bh) {
                printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id,
                                                                        ino);
-               make_bad_inode(inode);
-               return;
+               goto error;
        }
 
        off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
@@ -85,6 +89,12 @@ static void bfs_read_inode(struct inode *inode)
        inode->i_ctime.tv_nsec = 0;
 
        brelse(bh);
+       unlock_new_inode(inode);
+       return inode;
+
+error:
+       iget_failed(inode);
+       return ERR_PTR(-EIO);
 }
 
 static int bfs_write_inode(struct inode *inode, int unused)
@@ -276,7 +286,6 @@ static void destroy_inodecache(void)
 static const struct super_operations bfs_sops = {
        .alloc_inode    = bfs_alloc_inode,
        .destroy_inode  = bfs_destroy_inode,
-       .read_inode     = bfs_read_inode,
        .write_inode    = bfs_write_inode,
        .delete_inode   = bfs_delete_inode,
        .put_super      = bfs_put_super,
@@ -312,6 +321,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
        struct inode *inode;
        unsigned i, imap_len;
        struct bfs_sb_info *info;
+       long ret = -EINVAL;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
@@ -346,14 +356,16 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
                set_bit(i, info->si_imap);
 
        s->s_op = &bfs_sops;
-       inode = iget(s, BFS_ROOT_INO);
-       if (!inode) {
+       inode = bfs_iget(s, BFS_ROOT_INO);
+       if (IS_ERR(inode)) {
+               ret = PTR_ERR(inode);
                kfree(info->si_imap);
                goto out;
        }
        s->s_root = d_alloc_root(inode);
        if (!s->s_root) {
                iput(inode);
+               ret = -ENOMEM;
                kfree(info->si_imap);
                goto out;
        }
@@ -404,7 +416,7 @@ out:
        brelse(bh);
        kfree(info);
        s->s_fs_info = NULL;
-       return -EINVAL;
+       return ret;
 }
 
 static int bfs_get_sb(struct file_system_type *fs_type,
index 7596e1e94cde858df0ba7ea0907f9b86d1f4132e..7f65e71bf8595b6f5c5047dc86d26236b933c63c 100644 (file)
@@ -115,7 +115,7 @@ static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, u
        current->flags |= PF_DUMPCORE;
                strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm));
 #ifndef __sparc__
-       dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
+       dump.u_ar0 = offsetof(struct user, regs);
 #endif
        dump.signal = signr;
        dump_thread(regs, &dump);
index 4628c42ca892ef9248dc7a6dc0f1ed2134211de6..111771d38e6e2d457aa939ba35dafaee5dd28db3 100644 (file)
@@ -1077,7 +1077,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        current->mm->start_stack = bprm->p;
 
 #ifdef arch_randomize_brk
-       if (current->flags & PF_RANDOMIZE)
+       if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1))
                current->mm->brk = current->mm->start_brk =
                        arch_randomize_brk(current->mm);
 #endif
index e48a630ae266331f2ca7e482e0b8eeeea9f65d6b..e63067d25cdb9b839bae496e2f1110177b234e97 100644 (file)
@@ -534,7 +534,6 @@ void __init bdev_cache_init(void)
        if (err)
                panic("Cannot register bdev pseudo-fs");
        bd_mnt = kern_mount(&bd_type);
-       err = PTR_ERR(bd_mnt);
        if (IS_ERR(bd_mnt))
                panic("Cannot create bdev pseudo-fs");
        blockdev_superblock = bd_mnt->mnt_sb;   /* For writeback */
index e9f4ec7010926fb76e4808d3e4ed1bd0ab7f7cb5..fcc434227691fe4cbd57d2d74b7780c0767804fb 100644 (file)
@@ -147,10 +147,11 @@ cifs_read_super(struct super_block *sb, void *data,
 #endif
        sb->s_blocksize = CIFS_MAX_MSGSIZE;
        sb->s_blocksize_bits = 14;      /* default 2**14 = CIFS_MAX_MSGSIZE */
-       inode = iget(sb, ROOT_I);
+       inode = cifs_iget(sb, ROOT_I);
 
-       if (!inode) {
-               rc = -ENOMEM;
+       if (IS_ERR(inode)) {
+               rc = PTR_ERR(inode);
+               inode = NULL;
                goto out_no_root;
        }
 
@@ -520,7 +521,6 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data)
 }
 
 static const struct super_operations cifs_super_ops = {
-       .read_inode = cifs_read_inode,
        .put_super = cifs_put_super,
        .statfs = cifs_statfs,
        .alloc_inode = cifs_alloc_inode,
index 195b14de5567a17e4178e1846c27cab24036d4d8..68978306c3cad4333e7db69aa19e5eb7d1e89dfe 100644 (file)
@@ -44,6 +44,7 @@ extern void cifs_read_inode(struct inode *);
 
 /* Functions related to inodes */
 extern const struct inode_operations cifs_dir_inode_ops;
+extern struct inode *cifs_iget(struct super_block *, unsigned long);
 extern int cifs_create(struct inode *, struct dentry *, int,
                       struct nameidata *);
 extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
index 47f2621001e4e09069c2c390f77fb95a4d3dd15f..b1a4a65eaa08e0b24f1c1daf83700113f38a742b 100644 (file)
@@ -586,10 +586,18 @@ static const struct inode_operations cifs_ipc_inode_ops = {
 };
 
 /* gets root inode */
-void cifs_read_inode(struct inode *inode)
+struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
 {
-       int xid, rc;
+       int xid;
        struct cifs_sb_info *cifs_sb;
+       struct inode *inode;
+       long rc;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
 
        cifs_sb = CIFS_SB(inode->i_sb);
        xid = GetXid();
@@ -606,10 +614,18 @@ void cifs_read_inode(struct inode *inode)
                inode->i_fop = &simple_dir_operations;
                inode->i_uid = cifs_sb->mnt_uid;
                inode->i_gid = cifs_sb->mnt_gid;
+               _FreeXid(xid);
+               iget_failed(inode);
+               return ERR_PTR(rc);
        }
 
-       /* can not call macro FreeXid here since in a void func */
+       unlock_new_inode(inode);
+
+       /* can not call macro FreeXid here since in a void func
+        * TODO: This is no longer true
+        */
        _FreeXid(xid);
+       return inode;
 }
 
 int cifs_unlink(struct inode *inode, struct dentry *direntry)
index 69baca5ad6089d3303ef5839e35c51b3f4a07ef9..ee80ff341d37655d40cac120104a1cbd96f0fbcb 100644 (file)
@@ -2083,51 +2083,6 @@ long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
 
 #ifdef CONFIG_EPOLL
 
-#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT
-asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd,
-                       struct compat_epoll_event __user *event)
-{
-       long err = 0;
-       struct compat_epoll_event user;
-       struct epoll_event __user *kernel = NULL;
-
-       if (event) {
-               if (copy_from_user(&user, event, sizeof(user)))
-                       return -EFAULT;
-               kernel = compat_alloc_user_space(sizeof(struct epoll_event));
-               err |= __put_user(user.events, &kernel->events);
-               err |= __put_user(user.data, &kernel->data);
-       }
-
-       return err ? err : sys_epoll_ctl(epfd, op, fd, kernel);
-}
-
-
-asmlinkage long compat_sys_epoll_wait(int epfd,
-                       struct compat_epoll_event __user *events,
-                       int maxevents, int timeout)
-{
-       long i, ret, err = 0;
-       struct epoll_event __user *kbuf;
-       struct epoll_event ev;
-
-       if ((maxevents <= 0) ||
-                       (maxevents > (INT_MAX / sizeof(struct epoll_event))))
-               return -EINVAL;
-       kbuf = compat_alloc_user_space(sizeof(struct epoll_event) * maxevents);
-       ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout);
-       for (i = 0; i < ret; i++) {
-               err |= __get_user(ev.events, &kbuf[i].events);
-               err |= __get_user(ev.data, &kbuf[i].data);
-               err |= __put_user(ev.events, &events->events);
-               err |= __put_user_unaligned(ev.data, &events->data);
-               events++;
-       }
-
-       return err ? -EFAULT: ret;
-}
-#endif /* CONFIG_HAS_COMPAT_EPOLL_EVENT */
-
 #ifdef TIF_RESTORE_SIGMASK
 asmlinkage long compat_sys_epoll_pwait(int epfd,
                        struct compat_epoll_event __user *events,
@@ -2153,11 +2108,7 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
                sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
        }
 
-#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT
-       err = compat_sys_epoll_wait(epfd, events, maxevents, timeout);
-#else
        err = sys_epoll_wait(epfd, events, maxevents, timeout);
-#endif
 
        /*
         * If we changed the signal mask, we need to restore the original one.
index ffdc022cae64adb62b5108d259f08fa3057b1423..614bd75b5a4a38f476045953b4c897c7966a7e5e 100644 (file)
@@ -2986,7 +2986,7 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
        }
 
  do_ioctl:
-       error = vfs_ioctl(filp, fd, cmd, arg);
+       error = do_vfs_ioctl(filp, fd, cmd, arg);
  out_fput:
        fput_light(filp, fput_needed);
  out:
index d9ca1e5ceb92f02302fdeedb7bc1e2b6e5768f2e..44f6cf23b70e3baf4affccf31a68568aff7dd496 100644 (file)
@@ -89,7 +89,7 @@ static void d_free(struct dentry *dentry)
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
        /* if dentry was never inserted into hash, immediate free is OK */
-       if (dentry->d_hash.pprev == NULL)
+       if (hlist_unhashed(&dentry->d_hash))
                __d_free(dentry);
        else
                call_rcu(&dentry->d_u.d_rcu, d_callback);
@@ -1408,9 +1408,6 @@ void d_delete(struct dentry * dentry)
        if (atomic_read(&dentry->d_count) == 1) {
                dentry_iput(dentry);
                fsnotify_nameremove(dentry, isdir);
-
-               /* remove this and other inotify debug checks after 2.6.18 */
-               dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;
                return;
        }
 
index cee7c6f428f0fa518e80bda281eb92421a5ac295..def4e969df77646192eb6ce96d223a1f78ec4544 100644 (file)
@@ -696,9 +696,8 @@ static int dqinit_needed(struct inode *inode, int type)
 /* This routine is guarded by dqonoff_mutex mutex */
 static void add_dquot_ref(struct super_block *sb, int type)
 {
-       struct inode *inode;
+       struct inode *inode, *old_inode = NULL;
 
-restart:
        spin_lock(&inode_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                if (!atomic_read(&inode->i_writecount))
@@ -711,12 +710,18 @@ restart:
                __iget(inode);
                spin_unlock(&inode_lock);
 
+               iput(old_inode);
                sb->dq_op->initialize(inode, type);
-               iput(inode);
-               /* As we may have blocked we had better restart... */
-               goto restart;
+               /* We hold a reference to 'inode' so it couldn't have been
+                * removed from s_inodes list while we dropped the inode_lock.
+                * We cannot iput the inode now as we can be holding the last
+                * reference and we cannot iput it under inode_lock. So we
+                * keep the reference and iput it later. */
+               old_inode = inode;
+               spin_lock(&inode_lock);
        }
        spin_unlock(&inode_lock);
+       iput(old_inode);
 }
 
 /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */
index f8ef0af919e70d27acdb9292acbd0d3d95669bd7..a066e109ad9c05a7cbc0670f92045a3475e9aac1 100644 (file)
@@ -355,8 +355,11 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
        }
        /* Consider doing this once, when the file is opened */
        mutex_lock(&crypt_stat->cs_tfm_mutex);
-       rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
-                                    crypt_stat->key_size);
+       if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
+               rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
+                                            crypt_stat->key_size);
+               crypt_stat->flags |= ECRYPTFS_KEY_SET;
+       }
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
                                rc);
@@ -376,11 +379,10 @@ out:
  *
  * Convert an eCryptfs page index into a lower byte offset
  */
-void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
-                                     struct ecryptfs_crypt_stat *crypt_stat)
+static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
+                                            struct ecryptfs_crypt_stat *crypt_stat)
 {
-       (*offset) = ((crypt_stat->extent_size
-                     * crypt_stat->num_header_extents_at_front)
+       (*offset) = (crypt_stat->num_header_bytes_at_front
                     + (crypt_stat->extent_size * extent_num));
 }
 
@@ -842,15 +844,13 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)
        set_extent_mask_and_shift(crypt_stat);
        crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
        if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
-               crypt_stat->num_header_extents_at_front = 0;
+               crypt_stat->num_header_bytes_at_front = 0;
        else {
                if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)
-                       crypt_stat->num_header_extents_at_front =
-                               (ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE
-                                / crypt_stat->extent_size);
+                       crypt_stat->num_header_bytes_at_front =
+                               ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
                else
-                       crypt_stat->num_header_extents_at_front =
-                               (PAGE_CACHE_SIZE / crypt_stat->extent_size);
+                       crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE;
        }
 }
 
@@ -1128,7 +1128,7 @@ write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,
 
 struct ecryptfs_cipher_code_str_map_elem {
        char cipher_str[16];
-       u16 cipher_code;
+       u8 cipher_code;
 };
 
 /* Add support for additional ciphers by adding elements here. The
@@ -1152,10 +1152,10 @@ ecryptfs_cipher_code_str_map[] = {
  *
  * Returns zero on no match, or the cipher code on match
  */
-u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
+u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
 {
        int i;
-       u16 code = 0;
+       u8 code = 0;
        struct ecryptfs_cipher_code_str_map_elem *map =
                ecryptfs_cipher_code_str_map;
 
@@ -1187,7 +1187,7 @@ u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
  *
  * Returns zero on success
  */
-int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code)
+int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code)
 {
        int rc = 0;
        int i;
@@ -1236,7 +1236,8 @@ ecryptfs_write_header_metadata(char *virt,
 
        header_extent_size = (u32)crypt_stat->extent_size;
        num_header_extents_at_front =
-               (u16)crypt_stat->num_header_extents_at_front;
+               (u16)(crypt_stat->num_header_bytes_at_front
+                     / crypt_stat->extent_size);
        header_extent_size = cpu_to_be32(header_extent_size);
        memcpy(virt, &header_extent_size, 4);
        virt += 4;
@@ -1311,40 +1312,16 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size,
 static int
 ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
                                    struct dentry *ecryptfs_dentry,
-                                   char *page_virt)
+                                   char *virt)
 {
-       int current_header_page;
-       int header_pages;
        int rc;
 
-       rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt,
-                                 0, PAGE_CACHE_SIZE);
-       if (rc) {
+       rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt,
+                                 0, crypt_stat->num_header_bytes_at_front);
+       if (rc)
                printk(KERN_ERR "%s: Error attempting to write header "
                       "information to lower file; rc = [%d]\n", __FUNCTION__,
                       rc);
-               goto out;
-       }
-       header_pages = ((crypt_stat->extent_size
-                        * crypt_stat->num_header_extents_at_front)
-                       / PAGE_CACHE_SIZE);
-       memset(page_virt, 0, PAGE_CACHE_SIZE);
-       current_header_page = 1;
-       while (current_header_page < header_pages) {
-               loff_t offset;
-
-               offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT);
-               if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,
-                                              page_virt, offset,
-                                              PAGE_CACHE_SIZE))) {
-                       printk(KERN_ERR "%s: Error attempting to write header "
-                              "information to lower file; rc = [%d]\n",
-                              __FUNCTION__, rc);
-                       goto out;
-               }
-               current_header_page++;
-       }
-out:
        return rc;
 }
 
@@ -1370,15 +1347,13 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
  * retrieved via a prompt.  Exactly what happens at this point should
  * be policy-dependent.
  *
- * TODO: Support header information spanning multiple pages
- *
  * Returns zero on success; non-zero on error
  */
 int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
 {
        struct ecryptfs_crypt_stat *crypt_stat =
                &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
-       char *page_virt;
+       char *virt;
        size_t size = 0;
        int rc = 0;
 
@@ -1389,40 +1364,39 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
                        goto out;
                }
        } else {
+               printk(KERN_WARNING "%s: Encrypted flag not set\n",
+                      __FUNCTION__);
                rc = -EINVAL;
-               ecryptfs_printk(KERN_WARNING,
-                               "Called with crypt_stat->encrypted == 0\n");
                goto out;
        }
        /* Released in this function */
-       page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER);
-       if (!page_virt) {
-               ecryptfs_printk(KERN_ERR, "Out of memory\n");
+       virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL);
+       if (!virt) {
+               printk(KERN_ERR "%s: Out of memory\n", __FUNCTION__);
                rc = -ENOMEM;
                goto out;
        }
-       rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat,
-                                        ecryptfs_dentry);
+       rc = ecryptfs_write_headers_virt(virt, &size, crypt_stat,
+                                        ecryptfs_dentry);
        if (unlikely(rc)) {
-               ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n");
-               memset(page_virt, 0, PAGE_CACHE_SIZE);
+               printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
+                      __FUNCTION__, rc);
                goto out_free;
        }
        if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
                rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry,
-                                                     crypt_stat, page_virt,
-                                                     size);
+                                                     crypt_stat, virt, size);
        else
                rc = ecryptfs_write_metadata_to_contents(crypt_stat,
-                                                        ecryptfs_dentry,
-                                                        page_virt);
+                                                        ecryptfs_dentry, virt);
        if (rc) {
-               printk(KERN_ERR "Error writing metadata out to lower file; "
-                      "rc = [%d]\n", rc);
+               printk(KERN_ERR "%s: Error writing metadata out to lower file; "
+                      "rc = [%d]\n", __FUNCTION__, rc);
                goto out_free;
        }
 out_free:
-       kmem_cache_free(ecryptfs_header_cache_0, page_virt);
+       memset(virt, 0, crypt_stat->num_header_bytes_at_front);
+       kfree(virt);
 out:
        return rc;
 }
@@ -1442,16 +1416,16 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
        virt += sizeof(u32);
        memcpy(&num_header_extents_at_front, virt, sizeof(u16));
        num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
-       crypt_stat->num_header_extents_at_front =
-               (int)num_header_extents_at_front;
+       crypt_stat->num_header_bytes_at_front =
+               (((size_t)num_header_extents_at_front
+                 * (size_t)header_extent_size));
        (*bytes_read) = (sizeof(u32) + sizeof(u16));
        if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)
-           && ((crypt_stat->extent_size
-                * crypt_stat->num_header_extents_at_front)
+           && (crypt_stat->num_header_bytes_at_front
                < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {
                rc = -EINVAL;
-               printk(KERN_WARNING "Invalid number of header extents: [%zd]\n",
-                      crypt_stat->num_header_extents_at_front);
+               printk(KERN_WARNING "Invalid header size: [%zd]\n",
+                      crypt_stat->num_header_bytes_at_front);
        }
        return rc;
 }
@@ -1466,7 +1440,8 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
  */
 static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
 {
-       crypt_stat->num_header_extents_at_front = 2;
+       crypt_stat->num_header_bytes_at_front =
+               ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
 }
 
 /**
@@ -1552,9 +1527,10 @@ int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode)
        size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME,
                                       page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE);
        if (size < 0) {
-               printk(KERN_ERR "Error attempting to read the [%s] "
-                      "xattr from the lower file; return value = [%zd]\n",
-                      ECRYPTFS_XATTR_NAME, size);
+               if (unlikely(ecryptfs_verbosity > 0))
+                       printk(KERN_INFO "Error attempting to read the [%s] "
+                              "xattr from the lower file; return value = "
+                              "[%zd]\n", ECRYPTFS_XATTR_NAME, size);
                rc = -EINVAL;
                goto out;
        }
@@ -1802,7 +1778,7 @@ out:
 }
 
 struct kmem_cache *ecryptfs_key_tfm_cache;
-struct list_head key_tfm_list;
+static struct list_head key_tfm_list;
 struct mutex key_tfm_list_mutex;
 
 int ecryptfs_init_crypto(void)
@@ -1812,6 +1788,11 @@ int ecryptfs_init_crypto(void)
        return 0;
 }
 
+/**
+ * ecryptfs_destroy_crypto - free all cached key_tfms on key_tfm_list
+ *
+ * Called only at module unload time
+ */
 int ecryptfs_destroy_crypto(void)
 {
        struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp;
@@ -1835,6 +1816,8 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
        struct ecryptfs_key_tfm *tmp_tfm;
        int rc = 0;
 
+       BUG_ON(!mutex_is_locked(&key_tfm_list_mutex));
+
        tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL);
        if (key_tfm != NULL)
                (*key_tfm) = tmp_tfm;
@@ -1861,13 +1844,50 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
                        (*key_tfm) = NULL;
                goto out;
        }
-       mutex_lock(&key_tfm_list_mutex);
        list_add(&tmp_tfm->key_tfm_list, &key_tfm_list);
-       mutex_unlock(&key_tfm_list_mutex);
 out:
        return rc;
 }
 
+/**
+ * ecryptfs_tfm_exists - Search for existing tfm for cipher_name.
+ * @cipher_name: the name of the cipher to search for
+ * @key_tfm: set to corresponding tfm if found
+ *
+ * Searches for cached key_tfm matching @cipher_name
+ * Must be called with &key_tfm_list_mutex held
+ * Returns 1 if found, with @key_tfm set
+ * Returns 0 if not found, with @key_tfm set to NULL
+ */
+int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm)
+{
+       struct ecryptfs_key_tfm *tmp_key_tfm;
+
+       BUG_ON(!mutex_is_locked(&key_tfm_list_mutex));
+
+       list_for_each_entry(tmp_key_tfm, &key_tfm_list, key_tfm_list) {
+               if (strcmp(tmp_key_tfm->cipher_name, cipher_name) == 0) {
+                       if (key_tfm)
+                               (*key_tfm) = tmp_key_tfm;
+                       return 1;
+               }
+       }
+       if (key_tfm)
+               (*key_tfm) = NULL;
+       return 0;
+}
+
+/**
+ * ecryptfs_get_tfm_and_mutex_for_cipher_name
+ *
+ * @tfm: set to cached tfm found, or new tfm created
+ * @tfm_mutex: set to mutex for cached tfm found, or new tfm created
+ * @cipher_name: the name of the cipher to search for and/or add
+ *
+ * Sets pointers to @tfm & @tfm_mutex matching @cipher_name.
+ * Searches for cached item first, and creates new if not found.
+ * Returns 0 on success, non-zero if adding new cipher failed
+ */
 int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
                                               struct mutex **tfm_mutex,
                                               char *cipher_name)
@@ -1877,22 +1897,17 @@ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
 
        (*tfm) = NULL;
        (*tfm_mutex) = NULL;
+
        mutex_lock(&key_tfm_list_mutex);
-       list_for_each_entry(key_tfm, &key_tfm_list, key_tfm_list) {
-               if (strcmp(key_tfm->cipher_name, cipher_name) == 0) {
-                       (*tfm) = key_tfm->key_tfm;
-                       (*tfm_mutex) = &key_tfm->key_tfm_mutex;
-                       mutex_unlock(&key_tfm_list_mutex);
+       if (!ecryptfs_tfm_exists(cipher_name, &key_tfm)) {
+               rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0);
+               if (rc) {
+                       printk(KERN_ERR "Error adding new key_tfm to list; "
+                                       "rc = [%d]\n", rc);
                        goto out;
                }
        }
        mutex_unlock(&key_tfm_list_mutex);
-       rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0);
-       if (rc) {
-               printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n",
-                      rc);
-               goto out;
-       }
        (*tfm) = key_tfm->key_tfm;
        (*tfm_mutex) = &key_tfm->key_tfm_mutex;
 out:
index ce7a5d4aec36895014a60ee4771efadb94e40342..5007f788da01cec21fb39be75f714840ce6d29e9 100644 (file)
@@ -234,10 +234,11 @@ struct ecryptfs_crypt_stat {
 #define ECRYPTFS_KEY_VALID          0x00000080
 #define ECRYPTFS_METADATA_IN_XATTR  0x00000100
 #define ECRYPTFS_VIEW_AS_ENCRYPTED  0x00000200
+#define ECRYPTFS_KEY_SET            0x00000400
        u32 flags;
        unsigned int file_version;
        size_t iv_bytes;
-       size_t num_header_extents_at_front;
+       size_t num_header_bytes_at_front;
        size_t extent_size; /* Data extent size; default is 4096 */
        size_t key_size;
        size_t extent_shift;
@@ -322,7 +323,6 @@ struct ecryptfs_key_tfm {
        unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
 };
 
-extern struct list_head key_tfm_list;
 extern struct mutex key_tfm_list_mutex;
 
 /**
@@ -521,11 +521,9 @@ extern struct kmem_cache *ecryptfs_file_info_cache;
 extern struct kmem_cache *ecryptfs_dentry_info_cache;
 extern struct kmem_cache *ecryptfs_inode_info_cache;
 extern struct kmem_cache *ecryptfs_sb_info_cache;
-extern struct kmem_cache *ecryptfs_header_cache_0;
 extern struct kmem_cache *ecryptfs_header_cache_1;
 extern struct kmem_cache *ecryptfs_header_cache_2;
 extern struct kmem_cache *ecryptfs_xattr_cache;
-extern struct kmem_cache *ecryptfs_lower_page_cache;
 extern struct kmem_cache *ecryptfs_key_record_cache;
 extern struct kmem_cache *ecryptfs_key_sig_cache;
 extern struct kmem_cache *ecryptfs_global_auth_tok_cache;
@@ -562,8 +560,8 @@ int ecryptfs_read_and_validate_header_region(char *data,
                                             struct inode *ecryptfs_inode);
 int ecryptfs_read_and_validate_xattr_region(char *page_virt,
                                            struct dentry *ecryptfs_dentry);
-u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
-int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
+u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code);
 void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
 int ecryptfs_generate_key_packet_set(char *dest_base,
                                     struct ecryptfs_crypt_stat *crypt_stat,
@@ -576,8 +574,6 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
 int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
 int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
 void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
-ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
-                         size_t size);
 ssize_t
 ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,
                        void *value, size_t size);
@@ -623,6 +619,7 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
                         size_t key_size);
 int ecryptfs_init_crypto(void);
 int ecryptfs_destroy_crypto(void);
+int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm);
 int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
                                               struct mutex **tfm_mutex,
                                               char *cipher_name);
@@ -631,8 +628,6 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
                                      char *sig);
 int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start,
                         int num_zeros);
-void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
-                                     struct ecryptfs_crypt_stat *crypt_stat);
 int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
                         loff_t offset, size_t size);
 int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
@@ -646,8 +641,6 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
                                     pgoff_t page_index,
                                     size_t offset_in_page, size_t size,
                                     struct inode *ecryptfs_inode);
-int ecryptfs_read(char *data, loff_t offset, size_t size,
-                 struct file *ecryptfs_file);
 struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
 
 #endif /* #ifndef ECRYPTFS_KERNEL_H */
index c98c4690a771c78ad69d3188be2a595be081fa66..2b8f5ed4adea534063ae77259d366c426f9d5725 100644 (file)
@@ -209,9 +209,10 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
                        if (!(mount_crypt_stat->flags
                              & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
                                rc = -EIO;
-                               printk(KERN_WARNING "Attempt to read file that "
+                               printk(KERN_WARNING "Either the lower file "
                                       "is not in a valid eCryptfs format, "
-                                      "and plaintext passthrough mode is not "
+                                      "or the key could not be retrieved. "
+                                      "Plaintext passthrough mode is not "
                                       "enabled; returning -EIO\n");
                                mutex_unlock(&crypt_stat->cs_mutex);
                                goto out_free;
index 5a719180983cb36ebf3e264dc45c1559ebc209c0..edd1e44e9d474bdb46a5b7820192cef29c95cf92 100644 (file)
@@ -365,8 +365,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
                dentry->d_sb)->mount_crypt_stat;
        if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
                if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
-                       file_size = ((crypt_stat->extent_size
-                                     * crypt_stat->num_header_extents_at_front)
+                       file_size = (crypt_stat->num_header_bytes_at_front
                                     + i_size_read(lower_dentry->d_inode));
                else
                        file_size = i_size_read(lower_dentry->d_inode);
@@ -685,7 +684,7 @@ ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
  * @crypt_stat: Crypt_stat associated with file
  * @upper_size: Size of the upper file
  *
- * Calculate the requried size of the lower file based on the
+ * Calculate the required size of the lower file based on the
  * specified size of the upper file. This calculation is based on the
  * number of headers in the underlying file and the extent size.
  *
@@ -697,8 +696,7 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
 {
        loff_t lower_size;
 
-       lower_size = (crypt_stat->extent_size
-                     * crypt_stat->num_header_extents_at_front);
+       lower_size = crypt_stat->num_header_bytes_at_front;
        if (upper_size != 0) {
                loff_t num_extents;
 
@@ -875,11 +873,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
                        if (!(mount_crypt_stat->flags
                              & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
                                rc = -EIO;
-                               printk(KERN_WARNING "Attempt to read file that "
+                               printk(KERN_WARNING "Either the lower file "
                                       "is not in a valid eCryptfs format, "
-                                      "and plaintext passthrough mode is not "
+                                      "or the key could not be retrieved. "
+                                      "Plaintext passthrough mode is not "
                                       "enabled; returning -EIO\n");
-
                                mutex_unlock(&crypt_stat->cs_mutex);
                                goto out;
                        }
@@ -954,7 +952,7 @@ out:
        return rc;
 }
 
-ssize_t
+static ssize_t
 ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
                  size_t size)
 {
index f458c1f355655fcee80e3b8d4346d611686f3bc9..682b1b2482c26a062cefeaf924787242f89612d1 100644 (file)
@@ -189,7 +189,7 @@ out:
 }
 
 static int
-parse_tag_65_packet(struct ecryptfs_session_key *session_key, u16 *cipher_code,
+parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code,
                    struct ecryptfs_message *msg)
 {
        size_t i = 0;
@@ -275,7 +275,7 @@ out:
 
 
 static int
-write_tag_66_packet(char *signature, size_t cipher_code,
+write_tag_66_packet(char *signature, u8 cipher_code,
                    struct ecryptfs_crypt_stat *crypt_stat, char **packet,
                    size_t *packet_len)
 {
@@ -428,7 +428,7 @@ static int
 decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                                  struct ecryptfs_crypt_stat *crypt_stat)
 {
-       u16 cipher_code = 0;
+       u8 cipher_code = 0;
        struct ecryptfs_msg_ctx *msg_ctx;
        struct ecryptfs_message *msg = NULL;
        char *auth_tok_sig;
@@ -1537,7 +1537,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
        struct scatterlist dst_sg;
        struct scatterlist src_sg;
        struct mutex *tfm_mutex = NULL;
-       size_t cipher_code;
+       u8 cipher_code;
        size_t packet_size_length;
        size_t max_packet_size;
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
index 0249aa4ae181886cd2a26921a465feb5f8d27d41..778c420e4cac4c5d8bfda354c260e819106967c4 100644 (file)
@@ -117,7 +117,7 @@ void __ecryptfs_printk(const char *fmt, ...)
  *
  * Returns zero on success; non-zero otherwise
  */
-int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
+static int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
 {
        struct ecryptfs_inode_info *inode_info =
                ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
@@ -226,17 +226,15 @@ out:
        return rc;
 }
 
-enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug,
-       ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher,
-       ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes,
+enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,
+       ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher,
+       ecryptfs_opt_ecryptfs_key_bytes,
        ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,
        ecryptfs_opt_encrypted_view, ecryptfs_opt_err };
 
 static match_table_t tokens = {
        {ecryptfs_opt_sig, "sig=%s"},
        {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
-       {ecryptfs_opt_debug, "debug=%u"},
-       {ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"},
        {ecryptfs_opt_cipher, "cipher=%s"},
        {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"},
        {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"},
@@ -313,7 +311,6 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
        substring_t args[MAX_OPT_ARGS];
        int token;
        char *sig_src;
-       char *debug_src;
        char *cipher_name_dst;
        char *cipher_name_src;
        char *cipher_key_bytes_src;
@@ -341,16 +338,6 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
                        }
                        sig_set = 1;
                        break;
-               case ecryptfs_opt_debug:
-               case ecryptfs_opt_ecryptfs_debug:
-                       debug_src = args[0].from;
-                       ecryptfs_verbosity =
-                               (int)simple_strtol(debug_src, &debug_src,
-                                                  0);
-                       ecryptfs_printk(KERN_DEBUG,
-                                       "Verbosity set to [%d]" "\n",
-                                       ecryptfs_verbosity);
-                       break;
                case ecryptfs_opt_cipher:
                case ecryptfs_opt_ecryptfs_cipher:
                        cipher_name_src = args[0].from;
@@ -423,9 +410,13 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
        if (!cipher_key_bytes_set) {
                mount_crypt_stat->global_default_cipher_key_size = 0;
        }
-       rc = ecryptfs_add_new_key_tfm(
-               NULL, mount_crypt_stat->global_default_cipher_name,
-               mount_crypt_stat->global_default_cipher_key_size);
+       mutex_lock(&key_tfm_list_mutex);
+       if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name,
+                                NULL))
+               rc = ecryptfs_add_new_key_tfm(
+                       NULL, mount_crypt_stat->global_default_cipher_name,
+                       mount_crypt_stat->global_default_cipher_key_size);
+       mutex_unlock(&key_tfm_list_mutex);
        if (rc) {
                printk(KERN_ERR "Error attempting to initialize cipher with "
                       "name = [%s] and key size = [%td]; rc = [%d]\n",
@@ -653,11 +644,6 @@ static struct ecryptfs_cache_info {
                .name = "ecryptfs_sb_cache",
                .size = sizeof(struct ecryptfs_sb_info),
        },
-       {
-               .cache = &ecryptfs_header_cache_0,
-               .name = "ecryptfs_headers_0",
-               .size = PAGE_CACHE_SIZE,
-       },
        {
                .cache = &ecryptfs_header_cache_1,
                .name = "ecryptfs_headers_1",
@@ -821,6 +807,10 @@ static int __init ecryptfs_init(void)
                       "rc = [%d]\n", rc);
                goto out_release_messaging;
        }
+       if (ecryptfs_verbosity > 0)
+               printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values "
+                       "will be written to the syslog!\n", ecryptfs_verbosity);
+
        goto out;
 out_release_messaging:
        ecryptfs_release_messaging(ecryptfs_transport);
index 0535412d8c64a7793a64d5896c3c8ff031e5905f..dc74b186145d74db8a56470d5ef2e63ea5c0a3c0 100644 (file)
@@ -34,8 +34,6 @@
 #include <linux/scatterlist.h>
 #include "ecryptfs_kernel.h"
 
-struct kmem_cache *ecryptfs_lower_page_cache;
-
 /**
  * ecryptfs_get_locked_page
  *
@@ -102,13 +100,14 @@ static void set_header_info(char *page_virt,
                            struct ecryptfs_crypt_stat *crypt_stat)
 {
        size_t written;
-       int save_num_header_extents_at_front =
-               crypt_stat->num_header_extents_at_front;
+       size_t save_num_header_bytes_at_front =
+               crypt_stat->num_header_bytes_at_front;
 
-       crypt_stat->num_header_extents_at_front = 1;
+       crypt_stat->num_header_bytes_at_front =
+               ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
        ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written);
-       crypt_stat->num_header_extents_at_front =
-               save_num_header_extents_at_front;
+       crypt_stat->num_header_bytes_at_front =
+               save_num_header_bytes_at_front;
 }
 
 /**
@@ -134,8 +133,11 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
                loff_t view_extent_num = ((((loff_t)page->index)
                                           * num_extents_per_page)
                                          + extent_num_in_page);
+               size_t num_header_extents_at_front =
+                       (crypt_stat->num_header_bytes_at_front
+                        / crypt_stat->extent_size);
 
-               if (view_extent_num < crypt_stat->num_header_extents_at_front) {
+               if (view_extent_num < num_header_extents_at_front) {
                        /* This is a header extent */
                        char *page_virt;
 
@@ -157,9 +159,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
                } else {
                        /* This is an encrypted data extent */
                        loff_t lower_offset =
-                               ((view_extent_num -
-                                 crypt_stat->num_header_extents_at_front)
-                                * crypt_stat->extent_size);
+                               ((view_extent_num * crypt_stat->extent_size)
+                                - crypt_stat->num_header_bytes_at_front);
 
                        rc = ecryptfs_read_lower_page_segment(
                                page, (lower_offset >> PAGE_CACHE_SHIFT),
index 948f57624c05dd2bb1750ff05628f7931f44f2b7..0c4928623bbc414f7f0a4861e4dc727bfcdf132f 100644 (file)
@@ -293,6 +293,7 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
        return rc;
 }
 
+#if 0
 /**
  * ecryptfs_read
  * @data: The virtual address into which to write the data read (and
@@ -371,3 +372,4 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
 out:
        return rc;
 }
+#endif  /*  0  */
index 4859c4eecd654c8b7493f51fec4fee228a9f3d8f..c27ac2b358a12d7334003980b4b7d5fc8066cffa 100644 (file)
@@ -156,32 +156,38 @@ static void ecryptfs_clear_inode(struct inode *inode)
 /**
  * ecryptfs_show_options
  *
- * Prints the directory we are currently mounted over.
- * Returns zero on success; non-zero otherwise
+ * Prints the mount options for a given superblock.
+ * Returns zero; does not fail.
  */
 static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
 {
        struct super_block *sb = mnt->mnt_sb;
-       struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
-       struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root);
-       char *tmp_page;
-       char *path;
-       int rc = 0;
-
-       tmp_page = (char *)__get_free_page(GFP_KERNEL);
-       if (!tmp_page) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE);
-       if (IS_ERR(path)) {
-               rc = PTR_ERR(path);
-               goto out;
+       struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+               &ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
+       struct ecryptfs_global_auth_tok *walker;
+
+       mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
+       list_for_each_entry(walker,
+                           &mount_crypt_stat->global_auth_tok_list,
+                           mount_crypt_stat_list) {
+               seq_printf(m, ",ecryptfs_sig=%s", walker->sig);
        }
-       seq_printf(m, ",dir=%s", path);
-       free_page((unsigned long)tmp_page);
-out:
-       return rc;
+       mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
+
+       seq_printf(m, ",ecryptfs_cipher=%s",
+               mount_crypt_stat->global_default_cipher_name);
+
+       if (mount_crypt_stat->global_default_cipher_key_size)
+               seq_printf(m, ",ecryptfs_key_bytes=%zd",
+                          mount_crypt_stat->global_default_cipher_key_size);
+       if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)
+               seq_printf(m, ",ecryptfs_passthrough");
+       if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED)
+               seq_printf(m, ",ecryptfs_xattr_metadata");
+       if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED)
+               seq_printf(m, ",ecryptfs_encrypted_view");
+
+       return 0;
 }
 
 const struct super_operations ecryptfs_sops = {
index 174696f9bf14eb5c803d9200b89da6e97b68b5f0..627c3026946dcea30225a825f7335fb8c64ea454 100644 (file)
@@ -45,17 +45,26 @@ static inline void extent_copy(efs_extent *src, efs_extent *dst) {
        return;
 }
 
-void efs_read_inode(struct inode *inode)
+struct inode *efs_iget(struct super_block *super, unsigned long ino)
 {
        int i, inode_index;
        dev_t device;
        u32 rdev;
        struct buffer_head *bh;
-       struct efs_sb_info    *sb = SUPER_INFO(inode->i_sb);
-       struct efs_inode_info *in = INODE_INFO(inode);
+       struct efs_sb_info    *sb = SUPER_INFO(super);
+       struct efs_inode_info *in;
        efs_block_t block, offset;
        struct efs_dinode *efs_inode;
-  
+       struct inode *inode;
+
+       inode = iget_locked(super, ino);
+       if (IS_ERR(inode))
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       in = INODE_INFO(inode);
+
        /*
        ** EFS layout:
        **
@@ -159,13 +168,13 @@ void efs_read_inode(struct inode *inode)
                        break;
        }
 
-       return;
+       unlock_new_inode(inode);
+       return inode;
         
 read_inode_error:
        printk(KERN_WARNING "EFS: failed to read inode %lu\n", inode->i_ino);
-       make_bad_inode(inode);
-
-       return;
+       iget_failed(inode);
+       return ERR_PTR(-EIO);
 }
 
 static inline efs_block_t
index f7f407075be107e6dc0625676268300bdd1df501..e26704742d410df10af191bd2964ba70161d1b64 100644 (file)
@@ -66,9 +66,10 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
        lock_kernel();
        inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
        if (inodenum) {
-               if (!(inode = iget(dir->i_sb, inodenum))) {
+               inode = efs_iget(dir->i_sb, inodenum);
+               if (IS_ERR(inode)) {
                        unlock_kernel();
-                       return ERR_PTR(-EACCES);
+                       return ERR_CAST(inode);
                }
        }
        unlock_kernel();
@@ -84,12 +85,11 @@ static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino,
 
        if (ino == 0)
                return ERR_PTR(-ESTALE);
-       inode = iget(sb, ino);
-       if (inode == NULL)
-               return ERR_PTR(-ENOMEM);
+       inode = efs_iget(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
 
-       if (is_bad_inode(inode) ||
-           (generation && inode->i_generation != generation)) {
+       if (generation && inode->i_generation != generation) {
                iput(inode);
                return ERR_PTR(-ESTALE);
        }
@@ -116,7 +116,7 @@ struct dentry *efs_get_parent(struct dentry *child)
        struct dentry *parent;
        struct inode *inode;
        efs_ino_t ino;
-       int error;
+       long error;
 
        lock_kernel();
 
@@ -125,10 +125,11 @@ struct dentry *efs_get_parent(struct dentry *child)
        if (!ino)
                goto fail;
 
-       error = -EACCES;
-       inode = iget(child->d_inode->i_sb, ino);
-       if (!inode)
+       inode = efs_iget(child->d_inode->i_sb, ino);
+       if (IS_ERR(inode)) {
+               error = PTR_ERR(inode);
                goto fail;
+       }
 
        error = -ENOMEM;
        parent = d_alloc_anon(inode);
index c79bc627f1079adf72ac3779befdda1540272dec..14082405cdd16b7eb7fdde3367a4e339c36b37ce 100644 (file)
@@ -107,7 +107,6 @@ static int efs_remount(struct super_block *sb, int *flags, char *data)
 static const struct super_operations efs_superblock_operations = {
        .alloc_inode    = efs_alloc_inode,
        .destroy_inode  = efs_destroy_inode,
-       .read_inode     = efs_read_inode,
        .put_super      = efs_put_super,
        .statfs         = efs_statfs,
        .remount_fs     = efs_remount,
@@ -247,6 +246,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
        struct efs_sb_info *sb;
        struct buffer_head *bh;
        struct inode *root;
+       int ret = -EINVAL;
 
        sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
        if (!sb)
@@ -303,12 +303,18 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
        }
        s->s_op   = &efs_superblock_operations;
        s->s_export_op = &efs_export_ops;
-       root = iget(s, EFS_ROOTINODE);
+       root = efs_iget(s, EFS_ROOTINODE);
+       if (IS_ERR(root)) {
+               printk(KERN_ERR "EFS: get root inode failed\n");
+               ret = PTR_ERR(root);
+               goto out_no_fs;
+       }
+
        s->s_root = d_alloc_root(root);
        if (!(s->s_root)) {
-               printk(KERN_ERR "EFS: get root inode failed\n");
+               printk(KERN_ERR "EFS: get root dentry failed\n");
                iput(root);
+               ret = -ENOMEM;
                goto out_no_fs;
        }
 
@@ -318,7 +324,7 @@ out_no_fs_ul:
 out_no_fs:
        s->s_fs_info = NULL;
        kfree(sb);
-       return -EINVAL;
+       return ret;
 }
 
 static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
index 2ce19c000d2adb40afc17205edcb937cbb84d730..a9f130cd50ac2be6009ed2091fce0ec21d134fdd 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/spinlock.h>
 #include <linux/anon_inodes.h>
 #include <linux/eventfd.h>
+#include <linux/syscalls.h>
 
 struct eventfd_ctx {
        wait_queue_head_t wqh;
index 377ad172d74b1c5e8110393d875d5499f9bfe199..e7b2bafa1dd91cd69f8caf4597654a6355c3a666 100644 (file)
@@ -69,9 +69,53 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
        return desc + offset;
 }
 
+static int ext2_valid_block_bitmap(struct super_block *sb,
+                                       struct ext2_group_desc *desc,
+                                       unsigned int block_group,
+                                       struct buffer_head *bh)
+{
+       ext2_grpblk_t offset;
+       ext2_grpblk_t next_zero_bit;
+       ext2_fsblk_t bitmap_blk;
+       ext2_fsblk_t group_first_block;
+
+       group_first_block = ext2_group_first_block_no(sb, block_group);
+
+       /* check whether block bitmap block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+       offset = bitmap_blk - group_first_block;
+       if (!ext2_test_bit(offset, bh->b_data))
+               /* bad block bitmap */
+               goto err_out;
+
+       /* check whether the inode bitmap block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap);
+       offset = bitmap_blk - group_first_block;
+       if (!ext2_test_bit(offset, bh->b_data))
+               /* bad block bitmap */
+               goto err_out;
+
+       /* check whether the inode table block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_inode_table);
+       offset = bitmap_blk - group_first_block;
+       next_zero_bit = ext2_find_next_zero_bit(bh->b_data,
+                               offset + EXT2_SB(sb)->s_itb_per_group,
+                               offset);
+       if (next_zero_bit >= offset + EXT2_SB(sb)->s_itb_per_group)
+               /* good bitmap for inode tables */
+               return 1;
+
+err_out:
+       ext2_error(sb, __FUNCTION__,
+                       "Invalid block bitmap - "
+                       "block_group = %d, block = %lu",
+                       block_group, bitmap_blk);
+       return 0;
+}
+
 /*
- * Read the bitmap for a given block_group, reading into the specified 
- * slot in the superblock's bitmap cache.
+ * Read the bitmap for a given block_group,and validate the
+ * bits for block/inode/inode tables are set in the bitmaps
  *
  * Return buffer_head on success or NULL in case of failure.
  */
@@ -80,17 +124,36 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
 {
        struct ext2_group_desc * desc;
        struct buffer_head * bh = NULL;
-       
-       desc = ext2_get_group_desc (sb, block_group, NULL);
+       ext2_fsblk_t bitmap_blk;
+
+       desc = ext2_get_group_desc(sb, block_group, NULL);
        if (!desc)
-               goto error_out;
-       bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-       if (!bh)
-               ext2_error (sb, "read_block_bitmap",
+               return NULL;
+       bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+       bh = sb_getblk(sb, bitmap_blk);
+       if (unlikely(!bh)) {
+               ext2_error(sb, __FUNCTION__,
+                           "Cannot read block bitmap - "
+                           "block_group = %d, block_bitmap = %u",
+                           block_group, le32_to_cpu(desc->bg_block_bitmap));
+               return NULL;
+       }
+       if (likely(bh_uptodate_or_lock(bh)))
+               return bh;
+
+       if (bh_submit_read(bh) < 0) {
+               brelse(bh);
+               ext2_error(sb, __FUNCTION__,
                            "Cannot read block bitmap - "
                            "block_group = %d, block_bitmap = %u",
                            block_group, le32_to_cpu(desc->bg_block_bitmap));
-error_out:
+               return NULL;
+       }
+       if (!ext2_valid_block_bitmap(sb, desc, block_group, bh)) {
+               brelse(bh);
+               return NULL;
+       }
+
        return bh;
 }
 
@@ -474,11 +537,13 @@ do_more:
            in_range (block, le32_to_cpu(desc->bg_inode_table),
                      sbi->s_itb_per_group) ||
            in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table),
-                     sbi->s_itb_per_group))
+                     sbi->s_itb_per_group)) {
                ext2_error (sb, "ext2_free_blocks",
                            "Freeing blocks in system zones - "
                            "Block = %lu, count = %lu",
                            block, count);
+               goto error_return;
+       }
 
        for (i = 0, group_freed = 0; i < count; i++) {
                if (!ext2_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
@@ -1250,8 +1315,8 @@ retry_alloc:
        smp_rmb();
 
        /*
-        * Now search the rest of the groups.  We assume that 
-        * i and gdp correctly point to the last group visited.
+        * Now search the rest of the groups.  We assume that
+        * group_no and gdp correctly point to the last group visited.
         */
        for (bgi = 0; bgi < ngroups; bgi++) {
                group_no++;
@@ -1311,11 +1376,13 @@ allocated:
            in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),
                      EXT2_SB(sb)->s_itb_per_group) ||
            in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
-                     EXT2_SB(sb)->s_itb_per_group))
+                     EXT2_SB(sb)->s_itb_per_group)) {
                ext2_error(sb, "ext2_new_blocks",
                            "Allocating block in system zone - "
                            "blocks from "E2FSBLK", length %lu",
                            ret_block, num);
+               goto out;
+       }
 
        performed_allocation = 1;
 
@@ -1466,9 +1533,6 @@ int ext2_bg_has_super(struct super_block *sb, int group)
  */
 unsigned long ext2_bg_num_gdb(struct super_block *sb, int group)
 {
-       if (EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)&&
-           !ext2_group_sparse(group))
-               return 0;
-       return EXT2_SB(sb)->s_gdb_count;
+       return ext2_bg_has_super(sb, group) ? EXT2_SB(sb)->s_gdb_count : 0;
 }
 
index d868e26c15eba90e48c5c1324c9f207ef109d1e6..8dededd80fe2fa6747699c70b81d211b77d49ff0 100644 (file)
@@ -703,7 +703,7 @@ const struct file_operations ext2_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = ext2_readdir,
-       .ioctl          = ext2_ioctl,
+       .unlocked_ioctl = ext2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext2_compat_ioctl,
 #endif
index c87ae29c19cb346d86de36513d43a654ff3362e8..f1e5705e75f1f300fb7551c92f4d8983b27b23c9 100644 (file)
@@ -124,7 +124,7 @@ extern void ext2_check_inodes_bitmap (struct super_block *);
 extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
 
 /* inode.c */
-extern void ext2_read_inode (struct inode *);
+extern struct inode *ext2_iget (struct super_block *, unsigned long);
 extern int ext2_write_inode (struct inode *, int);
 extern void ext2_put_inode (struct inode *);
 extern void ext2_delete_inode (struct inode *);
@@ -139,8 +139,7 @@ int __ext2_write_begin(struct file *file, struct address_space *mapping,
                struct page **pagep, void **fsdata);
 
 /* ioctl.c */
-extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
-                      unsigned long);
+extern long ext2_ioctl(struct file *, unsigned int, unsigned long);
 extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 /* namei.c */
index c051798459a1c9faf33fa9b1c89508145c646c00..5f2fa9c36293d835722ec1371b820b07d5c5d9b5 100644 (file)
@@ -48,7 +48,7 @@ const struct file_operations ext2_file_operations = {
        .write          = do_sync_write,
        .aio_read       = generic_file_aio_read,
        .aio_write      = generic_file_aio_write,
-       .ioctl          = ext2_ioctl,
+       .unlocked_ioctl = ext2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext2_compat_ioctl,
 #endif
@@ -65,7 +65,7 @@ const struct file_operations ext2_xip_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = xip_file_read,
        .write          = xip_file_write,
-       .ioctl          = ext2_ioctl,
+       .unlocked_ioctl = ext2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext2_compat_ioctl,
 #endif
index b1ab32ab5a779381b1b46d29c61bd5fe2eddac44..c620068054277672aecefb90115c31daf26c4957 100644 (file)
@@ -286,15 +286,12 @@ static unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
  *     ext2_find_goal - find a prefered place for allocation.
  *     @inode: owner
  *     @block:  block we want
- *     @chain:  chain of indirect blocks
  *     @partial: pointer to the last triple within a chain
  *
  *     Returns preferred place for a block (the goal).
  */
 
-static inline int ext2_find_goal(struct inode *inode,
-                                long block,
-                                Indirect chain[4],
+static inline int ext2_find_goal(struct inode *inode, long block,
                                 Indirect *partial)
 {
        struct ext2_block_alloc_info *block_i;
@@ -569,7 +566,6 @@ static void ext2_splice_branch(struct inode *inode,
  *
  * `handle' can be NULL if create == 0.
  *
- * The BKL may not be held on entry here.  Be sure to take it early.
  * return > 0, # of blocks mapped or allocated.
  * return = 0, if plain lookup failed.
  * return < 0, error case.
@@ -639,7 +635,7 @@ reread:
        if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
                ext2_init_block_alloc_info(inode);
 
-       goal = ext2_find_goal(inode, iblock, chain, partial);
+       goal = ext2_find_goal(inode, iblock, partial);
 
        /* the number of blocks need to allocate for [d,t]indirect blocks */
        indirect_blks = (chain + depth) - partial - 1;
@@ -1185,22 +1181,33 @@ void ext2_get_inode_flags(struct ext2_inode_info *ei)
                ei->i_flags |= EXT2_DIRSYNC_FL;
 }
 
-void ext2_read_inode (struct inode * inode)
+struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
 {
-       struct ext2_inode_info *ei = EXT2_I(inode);
-       ino_t ino = inode->i_ino;
+       struct ext2_inode_info *ei;
        struct buffer_head * bh;
-       struct ext2_inode * raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
+       struct ext2_inode *raw_inode;
+       struct inode *inode;
+       long ret = -EIO;
        int n;
 
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       ei = EXT2_I(inode);
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
        ei->i_acl = EXT2_ACL_NOT_CACHED;
        ei->i_default_acl = EXT2_ACL_NOT_CACHED;
 #endif
        ei->i_block_alloc_info = NULL;
 
-       if (IS_ERR(raw_inode))
+       raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
+       if (IS_ERR(raw_inode)) {
+               ret = PTR_ERR(raw_inode);
                goto bad_inode;
+       }
 
        inode->i_mode = le16_to_cpu(raw_inode->i_mode);
        inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
@@ -1224,6 +1231,7 @@ void ext2_read_inode (struct inode * inode)
        if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {
                /* this inode is deleted */
                brelse (bh);
+               ret = -ESTALE;
                goto bad_inode;
        }
        inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
@@ -1290,11 +1298,12 @@ void ext2_read_inode (struct inode * inode)
        }
        brelse (bh);
        ext2_set_inode_flags(inode);
-       return;
+       unlock_new_inode(inode);
+       return inode;
        
 bad_inode:
-       make_bad_inode(inode);
-       return;
+       iget_failed(inode);
+       return ERR_PTR(ret);
 }
 
 static int ext2_update_inode(struct inode * inode, int do_sync)
index 320b2cb3d4d22eddf610d7a27d043eeef0437d5e..b8ea11fee5c6fc36e059f9dc873564e82a464ab0 100644 (file)
@@ -17,9 +17,9 @@
 #include <asm/uaccess.h>
 
 
-int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
-               unsigned long arg)
+long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = filp->f_dentry->d_inode;
        struct ext2_inode_info *ei = EXT2_I(inode);
        unsigned int flags;
        unsigned short rsv_window_size;
@@ -141,9 +141,6 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 #ifdef CONFIG_COMPAT
 long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       int ret;
-
        /* These are just misnamed, they actually get/put from/to user an int */
        switch (cmd) {
        case EXT2_IOC32_GETFLAGS:
@@ -161,9 +158,6 @@ long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        default:
                return -ENOIOCTLCMD;
        }
-       lock_kernel();
-       ret = ext2_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
-       unlock_kernel();
-       return ret;
+       return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
 }
 #endif
index e69beed839acb9bccbfc9f1f68c6bb2be9fdb5de..80c97fd8c571311280042d45343c9c220e458dd9 100644 (file)
@@ -63,9 +63,9 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
        ino = ext2_inode_by_name(dir, dentry);
        inode = NULL;
        if (ino) {
-               inode = iget(dir->i_sb, ino);
-               if (!inode)
-                       return ERR_PTR(-EACCES);
+               inode = ext2_iget(dir->i_sb, ino);
+               if (IS_ERR(inode))
+                       return ERR_CAST(inode);
        }
        return d_splice_alias(inode, dentry);
 }
@@ -83,10 +83,10 @@ struct dentry *ext2_get_parent(struct dentry *child)
        ino = ext2_inode_by_name(child->d_inode, &dotdot);
        if (!ino)
                return ERR_PTR(-ENOENT);
-       inode = iget(child->d_inode->i_sb, ino);
+       inode = ext2_iget(child->d_inode->i_sb, ino);
 
-       if (!inode)
-               return ERR_PTR(-EACCES);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
        parent = d_alloc_anon(inode);
        if (!parent) {
                iput(inode);
index 6abaf75163f0b17b1cbfb9b8b6e7ad563930bfdc..22f1010bf79f9f40cb9557d100694f2af9397f74 100644 (file)
@@ -234,16 +234,16 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
            le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) {
                seq_printf(seq, ",resgid=%u", sbi->s_resgid);
        }
-       if (test_opt(sb, ERRORS_CONT)) {
+       if (test_opt(sb, ERRORS_RO)) {
                int def_errors = le16_to_cpu(es->s_errors);
 
                if (def_errors == EXT2_ERRORS_PANIC ||
-                   def_errors == EXT2_ERRORS_RO) {
-                       seq_puts(seq, ",errors=continue");
+                   def_errors == EXT2_ERRORS_CONTINUE) {
+                       seq_puts(seq, ",errors=remount-ro");
                }
        }
-       if (test_opt(sb, ERRORS_RO))
-               seq_puts(seq, ",errors=remount-ro");
+       if (test_opt(sb, ERRORS_CONT))
+               seq_puts(seq, ",errors=continue");
        if (test_opt(sb, ERRORS_PANIC))
                seq_puts(seq, ",errors=panic");
        if (test_opt(sb, NO_UID32))
@@ -296,7 +296,6 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *da
 static const struct super_operations ext2_sops = {
        .alloc_inode    = ext2_alloc_inode,
        .destroy_inode  = ext2_destroy_inode,
-       .read_inode     = ext2_read_inode,
        .write_inode    = ext2_write_inode,
        .delete_inode   = ext2_delete_inode,
        .put_super      = ext2_put_super,
@@ -326,11 +325,10 @@ static struct inode *ext2_nfs_get_inode(struct super_block *sb,
         * it might be "neater" to call ext2_get_inode first and check
         * if the inode is valid.....
         */
-       inode = iget(sb, ino);
-       if (inode == NULL)
-               return ERR_PTR(-ENOMEM);
-       if (is_bad_inode(inode) ||
-           (generation && inode->i_generation != generation)) {
+       inode = ext2_iget(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       if (generation && inode->i_generation != generation) {
                /* we didn't find the right inode.. */
                iput(inode);
                return ERR_PTR(-ESTALE);
@@ -617,27 +615,24 @@ static int ext2_setup_super (struct super_block * sb,
        return res;
 }
 
-static int ext2_check_descriptors (struct super_block * sb)
+static int ext2_check_descriptors(struct super_block *sb)
 {
        int i;
-       int desc_block = 0;
        struct ext2_sb_info *sbi = EXT2_SB(sb);
        unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
        unsigned long last_block;
-       struct ext2_group_desc * gdp = NULL;
 
        ext2_debug ("Checking group descriptors");
 
-       for (i = 0; i < sbi->s_groups_count; i++)
-       {
+       for (i = 0; i < sbi->s_groups_count; i++) {
+               struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL);
+
                if (i == sbi->s_groups_count - 1)
                        last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
                else
                        last_block = first_block +
                                (EXT2_BLOCKS_PER_GROUP(sb) - 1);
 
-               if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
-                       gdp = (struct ext2_group_desc *) sbi->s_group_desc[desc_block++]->b_data;
                if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
                    le32_to_cpu(gdp->bg_block_bitmap) > last_block)
                {
@@ -667,7 +662,6 @@ static int ext2_check_descriptors (struct super_block * sb)
                        return 0;
                }
                first_block += EXT2_BLOCKS_PER_GROUP(sb);
-               gdp++;
        }
        return 1;
 }
@@ -750,6 +744,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        unsigned long logic_sb_block;
        unsigned long offset = 0;
        unsigned long def_mount_opts;
+       long ret = -EINVAL;
        int blocksize = BLOCK_SIZE;
        int db_count;
        int i, j;
@@ -820,10 +815,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        
        if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
                set_opt(sbi->s_mount_opt, ERRORS_PANIC);
-       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO)
-               set_opt(sbi->s_mount_opt, ERRORS_RO);
-       else
+       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE)
                set_opt(sbi->s_mount_opt, ERRORS_CONT);
+       else
+               set_opt(sbi->s_mount_opt, ERRORS_RO);
 
        sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
        sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
@@ -868,8 +863,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 
        blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
 
-       if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) ||
-                                 (sb->s_blocksize != blocksize))) {
+       if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) {
                if (!silent)
                        printk("XIP: Unsupported blocksize\n");
                goto failed_mount;
@@ -1046,19 +1040,24 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op = &ext2_sops;
        sb->s_export_op = &ext2_export_ops;
        sb->s_xattr = ext2_xattr_handlers;
-       root = iget(sb, EXT2_ROOT_INO);
-       sb->s_root = d_alloc_root(root);
-       if (!sb->s_root) {
-               iput(root);
-               printk(KERN_ERR "EXT2-fs: get root inode failed\n");
+       root = ext2_iget(sb, EXT2_ROOT_INO);
+       if (IS_ERR(root)) {
+               ret = PTR_ERR(root);
                goto failed_mount3;
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
-               dput(sb->s_root);
-               sb->s_root = NULL;
+               iput(root);
                printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
                goto failed_mount3;
        }
+
+       sb->s_root = d_alloc_root(root);
+       if (!sb->s_root) {
+               iput(root);
+               printk(KERN_ERR "EXT2-fs: get root inode failed\n");
+               ret = -ENOMEM;
+               goto failed_mount3;
+       }
        if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
                ext2_warning(sb, __FUNCTION__,
                        "mounting ext3 filesystem as ext2");
@@ -1085,7 +1084,7 @@ failed_mount:
 failed_sbi:
        sb->s_fs_info = NULL;
        kfree(sbi);
-       return -EINVAL;
+       return ret;
 }
 
 static void ext2_commit_super (struct super_block * sb,
index a8ba7e831278a0f53518edc101cd5517734af33e..a75713031105159ab82472301be86abef9ccc0af 100644 (file)
@@ -80,13 +80,57 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
        return desc + offset;
 }
 
+static int ext3_valid_block_bitmap(struct super_block *sb,
+                                       struct ext3_group_desc *desc,
+                                       unsigned int block_group,
+                                       struct buffer_head *bh)
+{
+       ext3_grpblk_t offset;
+       ext3_grpblk_t next_zero_bit;
+       ext3_fsblk_t bitmap_blk;
+       ext3_fsblk_t group_first_block;
+
+       group_first_block = ext3_group_first_block_no(sb, block_group);
+
+       /* check whether block bitmap block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+       offset = bitmap_blk - group_first_block;
+       if (!ext3_test_bit(offset, bh->b_data))
+               /* bad block bitmap */
+               goto err_out;
+
+       /* check whether the inode bitmap block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap);
+       offset = bitmap_blk - group_first_block;
+       if (!ext3_test_bit(offset, bh->b_data))
+               /* bad block bitmap */
+               goto err_out;
+
+       /* check whether the inode table block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_inode_table);
+       offset = bitmap_blk - group_first_block;
+       next_zero_bit = ext3_find_next_zero_bit(bh->b_data,
+                               offset + EXT3_SB(sb)->s_itb_per_group,
+                               offset);
+       if (next_zero_bit >= offset + EXT3_SB(sb)->s_itb_per_group)
+               /* good bitmap for inode tables */
+               return 1;
+
+err_out:
+       ext3_error(sb, __FUNCTION__,
+                       "Invalid block bitmap - "
+                       "block_group = %d, block = %lu",
+                       block_group, bitmap_blk);
+       return 0;
+}
+
 /**
  * read_block_bitmap()
  * @sb:                        super block
  * @block_group:       given block group
  *
- * Read the bitmap for a given block_group, reading into the specified
- * slot in the superblock's bitmap cache.
+ * Read the bitmap for a given block_group,and validate the
+ * bits for block/inode/inode tables are set in the bitmaps
  *
  * Return buffer_head on success or NULL in case of failure.
  */
@@ -95,17 +139,35 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
 {
        struct ext3_group_desc * desc;
        struct buffer_head * bh = NULL;
+       ext3_fsblk_t bitmap_blk;
 
-       desc = ext3_get_group_desc (sb, block_group, NULL);
+       desc = ext3_get_group_desc(sb, block_group, NULL);
        if (!desc)
-               goto error_out;
-       bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-       if (!bh)
-               ext3_error (sb, "read_block_bitmap",
+               return NULL;
+       bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+       bh = sb_getblk(sb, bitmap_blk);
+       if (unlikely(!bh)) {
+               ext3_error(sb, __FUNCTION__,
                            "Cannot read block bitmap - "
                            "block_group = %d, block_bitmap = %u",
                            block_group, le32_to_cpu(desc->bg_block_bitmap));
-error_out:
+               return NULL;
+       }
+       if (likely(bh_uptodate_or_lock(bh)))
+               return bh;
+
+       if (bh_submit_read(bh) < 0) {
+               brelse(bh);
+               ext3_error(sb, __FUNCTION__,
+                           "Cannot read block bitmap - "
+                           "block_group = %d, block_bitmap = %u",
+                           block_group, le32_to_cpu(desc->bg_block_bitmap));
+               return NULL;
+       }
+       if (!ext3_valid_block_bitmap(sb, desc, block_group, bh)) {
+               brelse(bh);
+               return NULL;
+       }
        return bh;
 }
 /*
@@ -468,11 +530,13 @@ do_more:
            in_range (block, le32_to_cpu(desc->bg_inode_table),
                      sbi->s_itb_per_group) ||
            in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table),
-                     sbi->s_itb_per_group))
+                     sbi->s_itb_per_group)) {
                ext3_error (sb, "ext3_free_blocks",
                            "Freeing blocks in system zones - "
                            "Block = "E3FSBLK", count = %lu",
                            block, count);
+               goto error_return;
+       }
 
        /*
         * We are about to start releasing blocks in the bitmap,
@@ -1508,7 +1572,7 @@ retry_alloc:
 
        /*
         * Now search the rest of the groups.  We assume that
-        * i and gdp correctly point to the last group visited.
+        * group_no and gdp correctly point to the last group visited.
         */
        for (bgi = 0; bgi < ngroups; bgi++) {
                group_no++;
@@ -1575,11 +1639,13 @@ allocated:
            in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),
                      EXT3_SB(sb)->s_itb_per_group) ||
            in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
-                     EXT3_SB(sb)->s_itb_per_group))
+                     EXT3_SB(sb)->s_itb_per_group)) {
                ext3_error(sb, "ext3_new_block",
                            "Allocating block in system zone - "
                            "blocks from "E3FSBLK", length %lu",
                             ret_block, num);
+               goto out;
+       }
 
        performed_allocation = 1;
 
@@ -1782,11 +1848,7 @@ static unsigned long ext3_bg_num_gdb_meta(struct super_block *sb, int group)
 
 static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group)
 {
-       if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
-                       !ext3_group_sparse(group))
-               return 0;
-       return EXT3_SB(sb)->s_gdb_count;
+       return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0;
 }
 
 /**
index 1bc8cd89c51d33b7f57607003d06b3fe4036a1ce..58ae2f943f12c64d863312214bebd6fe2e908a52 100644 (file)
@@ -642,14 +642,15 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
        unsigned long max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count);
        unsigned long block_group;
        int bit;
-       struct buffer_head *bitmap_bh = NULL;
+       struct buffer_head *bitmap_bh;
        struct inode *inode = NULL;
+       long err = -EIO;
 
        /* Error cases - e2fsck has already cleaned up for us */
        if (ino > max_ino) {
                ext3_warning(sb, __FUNCTION__,
                             "bad orphan ino %lu!  e2fsck was run?", ino);
-               goto out;
+               goto error;
        }
 
        block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
@@ -658,38 +659,49 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
        if (!bitmap_bh) {
                ext3_warning(sb, __FUNCTION__,
                             "inode bitmap error for orphan %lu", ino);
-               goto out;
+               goto error;
        }
 
        /* Having the inode bit set should be a 100% indicator that this
         * is a valid orphan (no e2fsck run on fs).  Orphans also include
         * inodes that were being truncated, so we can't check i_nlink==0.
         */
-       if (!ext3_test_bit(bit, bitmap_bh->b_data) ||
-                       !(inode = iget(sb, ino)) || is_bad_inode(inode) ||
-                       NEXT_ORPHAN(inode) > max_ino) {
-               ext3_warning(sb, __FUNCTION__,
-                            "bad orphan inode %lu!  e2fsck was run?", ino);
-               printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n",
-                      bit, (unsigned long long)bitmap_bh->b_blocknr,
-                      ext3_test_bit(bit, bitmap_bh->b_data));
-               printk(KERN_NOTICE "inode=%p\n", inode);
-               if (inode) {
-                       printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
-                              is_bad_inode(inode));
-                       printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
-                              NEXT_ORPHAN(inode));
-                       printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
-               }
+       if (!ext3_test_bit(bit, bitmap_bh->b_data))
+               goto bad_orphan;
+
+       inode = ext3_iget(sb, ino);
+       if (IS_ERR(inode))
+               goto iget_failed;
+
+       if (NEXT_ORPHAN(inode) > max_ino)
+               goto bad_orphan;
+       brelse(bitmap_bh);
+       return inode;
+
+iget_failed:
+       err = PTR_ERR(inode);
+       inode = NULL;
+bad_orphan:
+       ext3_warning(sb, __FUNCTION__,
+                    "bad orphan inode %lu!  e2fsck was run?", ino);
+       printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n",
+              bit, (unsigned long long)bitmap_bh->b_blocknr,
+              ext3_test_bit(bit, bitmap_bh->b_data));
+       printk(KERN_NOTICE "inode=%p\n", inode);
+       if (inode) {
+               printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
+                      is_bad_inode(inode));
+               printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
+                      NEXT_ORPHAN(inode));
+               printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
                /* Avoid freeing blocks if we got a bad deleted inode */
-               if (inode && inode->i_nlink == 0)
+               if (inode->i_nlink == 0)
                        inode->i_blocks = 0;
                iput(inode);
-               inode = NULL;
        }
-out:
        brelse(bitmap_bh);
-       return inode;
+error:
+       return ERR_PTR(err);
 }
 
 unsigned long ext3_count_free_inodes (struct super_block * sb)
index 07753543928865399d1be5bd9d551c52a006369b..eb95670a27ebafac6a9a4c593ef37e98a0f29ebf 100644 (file)
@@ -439,16 +439,14 @@ static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind)
  *     ext3_find_goal - find a prefered place for allocation.
  *     @inode: owner
  *     @block:  block we want
- *     @chain:  chain of indirect blocks
  *     @partial: pointer to the last triple within a chain
- *     @goal:  place to store the result.
  *
  *     Normally this function find the prefered place for block allocation,
- *     stores it in *@goal and returns zero.
+ *     returns it.
  */
 
 static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block,
-               Indirect chain[4], Indirect *partial)
+                                  Indirect *partial)
 {
        struct ext3_block_alloc_info *block_i;
 
@@ -884,7 +882,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
        if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
                ext3_init_block_alloc_info(inode);
 
-       goal = ext3_find_goal(inode, iblock, chain, partial);
+       goal = ext3_find_goal(inode, iblock, partial);
 
        /* the number of blocks need to allocate for [d,t]indirect blocks */
        indirect_blks = (chain + depth) - partial - 1;
@@ -941,55 +939,45 @@ out:
        return err;
 }
 
-#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32)
+/* Maximum number of blocks we map for direct IO at once. */
+#define DIO_MAX_BLOCKS 4096
+/*
+ * Number of credits we need for writing DIO_MAX_BLOCKS:
+ * We need sb + group descriptor + bitmap + inode -> 4
+ * For B blocks with A block pointers per block we need:
+ * 1 (triple ind.) + (B/A/A + 2) (doubly ind.) + (B/A + 2) (indirect).
+ * If we plug in 4096 for B and 256 for A (for 1KB block size), we get 25.
+ */
+#define DIO_CREDITS 25
 
 static int ext3_get_block(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create)
 {
        handle_t *handle = ext3_journal_current_handle();
-       int ret = 0;
+       int ret = 0, started = 0;
        unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
 
-       if (!create)
-               goto get_block;         /* A read */
-
-       if (max_blocks == 1)
-               goto get_block;         /* A single block get */
-
-       if (handle->h_transaction->t_state == T_LOCKED) {
-               /*
-                * Huge direct-io writes can hold off commits for long
-                * periods of time.  Let this commit run.
-                */
-               ext3_journal_stop(handle);
-               handle = ext3_journal_start(inode, DIO_CREDITS);
-               if (IS_ERR(handle))
+       if (create && !handle) {        /* Direct IO write... */
+               if (max_blocks > DIO_MAX_BLOCKS)
+                       max_blocks = DIO_MAX_BLOCKS;
+               handle = ext3_journal_start(inode, DIO_CREDITS +
+                               2 * EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb));
+               if (IS_ERR(handle)) {
                        ret = PTR_ERR(handle);
-               goto get_block;
-       }
-
-       if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) {
-               /*
-                * Getting low on buffer credits...
-                */
-               ret = ext3_journal_extend(handle, DIO_CREDITS);
-               if (ret > 0) {
-                       /*
-                        * Couldn't extend the transaction.  Start a new one.
-                        */
-                       ret = ext3_journal_restart(handle, DIO_CREDITS);
+                       goto out;
                }
+               started = 1;
        }
 
-get_block:
-       if (ret == 0) {
-               ret = ext3_get_blocks_handle(handle, inode, iblock,
+       ret = ext3_get_blocks_handle(handle, inode, iblock,
                                        max_blocks, bh_result, create, 0);
-               if (ret > 0) {
-                       bh_result->b_size = (ret << inode->i_blkbits);
-                       ret = 0;
-               }
+       if (ret > 0) {
+               bh_result->b_size = (ret << inode->i_blkbits);
+               ret = 0;
        }
+       if (started)
+               ext3_journal_stop(handle);
+out:
        return ret;
 }
 
@@ -1680,7 +1668,8 @@ static int ext3_releasepage(struct page *page, gfp_t wait)
  * if the machine crashes during the write.
  *
  * If the O_DIRECT write is intantiating holes inside i_size and the machine
- * crashes then stale disk data _may_ be exposed inside the file.
+ * crashes then stale disk data _may_ be exposed inside the file. But current
+ * VFS code falls back into buffered path in that case so we are safe.
  */
 static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
                        const struct iovec *iov, loff_t offset,
@@ -1689,7 +1678,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
        struct ext3_inode_info *ei = EXT3_I(inode);
-       handle_t *handle = NULL;
+       handle_t *handle;
        ssize_t ret;
        int orphan = 0;
        size_t count = iov_length(iov, nr_segs);
@@ -1697,17 +1686,21 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
        if (rw == WRITE) {
                loff_t final_size = offset + count;
 
-               handle = ext3_journal_start(inode, DIO_CREDITS);
-               if (IS_ERR(handle)) {
-                       ret = PTR_ERR(handle);
-                       goto out;
-               }
                if (final_size > inode->i_size) {
+                       /* Credits for sb + inode write */
+                       handle = ext3_journal_start(inode, 2);
+                       if (IS_ERR(handle)) {
+                               ret = PTR_ERR(handle);
+                               goto out;
+                       }
                        ret = ext3_orphan_add(handle, inode);
-                       if (ret)
-                               goto out_stop;
+                       if (ret) {
+                               ext3_journal_stop(handle);
+                               goto out;
+                       }
                        orphan = 1;
                        ei->i_disksize = inode->i_size;
+                       ext3_journal_stop(handle);
                }
        }
 
@@ -1715,18 +1708,21 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
                                 offset, nr_segs,
                                 ext3_get_block, NULL);
 
-       /*
-        * Reacquire the handle: ext3_get_block() can restart the transaction
-        */
-       handle = ext3_journal_current_handle();
-
-out_stop:
-       if (handle) {
+       if (orphan) {
                int err;
 
-               if (orphan && inode->i_nlink)
+               /* Credits for sb + inode write */
+               handle = ext3_journal_start(inode, 2);
+               if (IS_ERR(handle)) {
+                       /* This is really bad luck. We've written the data
+                        * but cannot extend i_size. Bail out and pretend
+                        * the write failed... */
+                       ret = PTR_ERR(handle);
+                       goto out;
+               }
+               if (inode->i_nlink)
                        ext3_orphan_del(handle, inode);
-               if (orphan && ret > 0) {
+               if (ret > 0) {
                        loff_t end = offset + ret;
                        if (end > inode->i_size) {
                                ei->i_disksize = end;
@@ -2658,21 +2654,31 @@ void ext3_get_inode_flags(struct ext3_inode_info *ei)
                ei->i_flags |= EXT3_DIRSYNC_FL;
 }
 
-void ext3_read_inode(struct inode * inode)
+struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
 {
        struct ext3_iloc iloc;
        struct ext3_inode *raw_inode;
-       struct ext3_inode_info *ei = EXT3_I(inode);
+       struct ext3_inode_info *ei;
        struct buffer_head *bh;
+       struct inode *inode;
+       long ret;
        int block;
 
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       ei = EXT3_I(inode);
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
        ei->i_acl = EXT3_ACL_NOT_CACHED;
        ei->i_default_acl = EXT3_ACL_NOT_CACHED;
 #endif
        ei->i_block_alloc_info = NULL;
 
-       if (__ext3_get_inode_loc(inode, &iloc, 0))
+       ret = __ext3_get_inode_loc(inode, &iloc, 0);
+       if (ret < 0)
                goto bad_inode;
        bh = iloc.bh;
        raw_inode = ext3_raw_inode(&iloc);
@@ -2703,6 +2709,7 @@ void ext3_read_inode(struct inode * inode)
                    !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ORPHAN_FS)) {
                        /* this inode is deleted */
                        brelse (bh);
+                       ret = -ESTALE;
                        goto bad_inode;
                }
                /* The only unlinked inodes we let through here have
@@ -2746,6 +2753,7 @@ void ext3_read_inode(struct inode * inode)
                if (EXT3_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
                    EXT3_INODE_SIZE(inode->i_sb)) {
                        brelse (bh);
+                       ret = -EIO;
                        goto bad_inode;
                }
                if (ei->i_extra_isize == 0) {
@@ -2787,11 +2795,12 @@ void ext3_read_inode(struct inode * inode)
        }
        brelse (iloc.bh);
        ext3_set_inode_flags(inode);
-       return;
+       unlock_new_inode(inode);
+       return inode;
 
 bad_inode:
-       make_bad_inode(inode);
-       return;
+       iget_failed(inode);
+       return ERR_PTR(ret);
 }
 
 /*
index 4ab6f76e63d0cda8e125672153571038f48b16c6..dec3e0d88ab1536745ccf52c70a23a2a6a04ca57 100644 (file)
@@ -860,14 +860,10 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
        int nblocks, i, err;
        struct inode *dir = dentry->d_parent->d_inode;
        int namelen;
-       const u8 *name;
-       unsigned blocksize;
 
        *res_dir = NULL;
        sb = dir->i_sb;
-       blocksize = sb->s_blocksize;
        namelen = dentry->d_name.len;
-       name = dentry->d_name.name;
        if (namelen > EXT3_NAME_LEN)
                return NULL;
        if (is_dx(dir)) {
@@ -1041,17 +1037,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
                if (!ext3_valid_inum(dir->i_sb, ino)) {
                        ext3_error(dir->i_sb, "ext3_lookup",
                                   "bad inode number: %lu", ino);
-                       inode = NULL;
-               } else
-                       inode = iget(dir->i_sb, ino);
-
-               if (!inode)
-                       return ERR_PTR(-EACCES);
-
-               if (is_bad_inode(inode)) {
-                       iput(inode);
-                       return ERR_PTR(-ENOENT);
+                       return ERR_PTR(-EIO);
                }
+               inode = ext3_iget(dir->i_sb, ino);
+               if (IS_ERR(inode))
+                       return ERR_CAST(inode);
        }
        return d_splice_alias(inode, dentry);
 }
@@ -1080,18 +1070,13 @@ struct dentry *ext3_get_parent(struct dentry *child)
        if (!ext3_valid_inum(child->d_inode->i_sb, ino)) {
                ext3_error(child->d_inode->i_sb, "ext3_get_parent",
                           "bad inode number: %lu", ino);
-               inode = NULL;
-       } else
-               inode = iget(child->d_inode->i_sb, ino);
-
-       if (!inode)
-               return ERR_PTR(-EACCES);
-
-       if (is_bad_inode(inode)) {
-               iput(inode);
-               return ERR_PTR(-ENOENT);
+               return ERR_PTR(-EIO);
        }
 
+       inode = ext3_iget(child->d_inode->i_sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+
        parent = d_alloc_anon(inode);
        if (!parent) {
                iput(inode);
index 44de1453c30158e5bc742d2cfc54cf56d5ec0724..ebc05af7343aecb669304b4914359534834ac108 100644 (file)
@@ -795,12 +795,11 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
                                     "No reserved GDT blocks, can't resize");
                        return -EPERM;
                }
-               inode = iget(sb, EXT3_RESIZE_INO);
-               if (!inode || is_bad_inode(inode)) {
+               inode = ext3_iget(sb, EXT3_RESIZE_INO);
+               if (IS_ERR(inode)) {
                        ext3_warning(sb, __FUNCTION__,
                                     "Error opening resize inode");
-                       iput(inode);
-                       return -ENOENT;
+                       return PTR_ERR(inode);
                }
        }
 
index f3675cc630e97a7c5ab42251193050872957c5c1..cf2a2c3660ec793b4e20d090bd16e6192d824644 100644 (file)
@@ -575,16 +575,16 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
            le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) {
                seq_printf(seq, ",resgid=%u", sbi->s_resgid);
        }
-       if (test_opt(sb, ERRORS_CONT)) {
+       if (test_opt(sb, ERRORS_RO)) {
                int def_errors = le16_to_cpu(es->s_errors);
 
                if (def_errors == EXT3_ERRORS_PANIC ||
-                   def_errors == EXT3_ERRORS_RO) {
-                       seq_puts(seq, ",errors=continue");
+                   def_errors == EXT3_ERRORS_CONTINUE) {
+                       seq_puts(seq, ",errors=remount-ro");
                }
        }
-       if (test_opt(sb, ERRORS_RO))
-               seq_puts(seq, ",errors=remount-ro");
+       if (test_opt(sb, ERRORS_CONT))
+               seq_puts(seq, ",errors=continue");
        if (test_opt(sb, ERRORS_PANIC))
                seq_puts(seq, ",errors=panic");
        if (test_opt(sb, NO_UID32))
@@ -649,11 +649,10 @@ static struct inode *ext3_nfs_get_inode(struct super_block *sb,
         * Currently we don't know the generation for parent directory, so
         * a generation of 0 means "accept any"
         */
-       inode = iget(sb, ino);
-       if (inode == NULL)
-               return ERR_PTR(-ENOMEM);
-       if (is_bad_inode(inode) ||
-           (generation && inode->i_generation != generation)) {
+       inode = ext3_iget(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       if (generation && inode->i_generation != generation) {
                iput(inode);
                return ERR_PTR(-ESTALE);
        }
@@ -722,7 +721,6 @@ static struct quotactl_ops ext3_qctl_operations = {
 static const struct super_operations ext3_sops = {
        .alloc_inode    = ext3_alloc_inode,
        .destroy_inode  = ext3_destroy_inode,
-       .read_inode     = ext3_read_inode,
        .write_inode    = ext3_write_inode,
        .dirty_inode    = ext3_dirty_inode,
        .delete_inode   = ext3_delete_inode,
@@ -1252,28 +1250,24 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
 }
 
 /* Called at mount-time, super-block is locked */
-static int ext3_check_descriptors (struct super_block * sb)
+static int ext3_check_descriptors(struct super_block *sb)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
        ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
        ext3_fsblk_t last_block;
-       struct ext3_group_desc * gdp = NULL;
-       int desc_block = 0;
        int i;
 
        ext3_debug ("Checking group descriptors");
 
-       for (i = 0; i < sbi->s_groups_count; i++)
-       {
+       for (i = 0; i < sbi->s_groups_count; i++) {
+               struct ext3_group_desc *gdp = ext3_get_group_desc(sb, i, NULL);
+
                if (i == sbi->s_groups_count - 1)
                        last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
                else
                        last_block = first_block +
                                (EXT3_BLOCKS_PER_GROUP(sb) - 1);
 
-               if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0)
-                       gdp = (struct ext3_group_desc *)
-                                       sbi->s_group_desc[desc_block++]->b_data;
                if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
                    le32_to_cpu(gdp->bg_block_bitmap) > last_block)
                {
@@ -1306,7 +1300,6 @@ static int ext3_check_descriptors (struct super_block * sb)
                        return 0;
                }
                first_block += EXT3_BLOCKS_PER_GROUP(sb);
-               gdp++;
        }
 
        sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb));
@@ -1383,8 +1376,8 @@ static void ext3_orphan_cleanup (struct super_block * sb,
        while (es->s_last_orphan) {
                struct inode *inode;
 
-               if (!(inode =
-                     ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) {
+               inode = ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan));
+               if (IS_ERR(inode)) {
                        es->s_last_orphan = 0;
                        break;
                }
@@ -1513,6 +1506,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        int db_count;
        int i;
        int needs_recovery;
+       int ret = -EINVAL;
        __le32 features;
        int err;
 
@@ -1583,10 +1577,10 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
 
        if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC)
                set_opt(sbi->s_mount_opt, ERRORS_PANIC);
-       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO)
-               set_opt(sbi->s_mount_opt, ERRORS_RO);
-       else
+       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_CONTINUE)
                set_opt(sbi->s_mount_opt, ERRORS_CONT);
+       else
+               set_opt(sbi->s_mount_opt, ERRORS_RO);
 
        sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
        sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
@@ -1882,19 +1876,24 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
         * so we can safely mount the rest of the filesystem now.
         */
 
-       root = iget(sb, EXT3_ROOT_INO);
-       sb->s_root = d_alloc_root(root);
-       if (!sb->s_root) {
+       root = ext3_iget(sb, EXT3_ROOT_INO);
+       if (IS_ERR(root)) {
                printk(KERN_ERR "EXT3-fs: get root inode failed\n");
-               iput(root);
+               ret = PTR_ERR(root);
                goto failed_mount4;
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
-               dput(sb->s_root);
-               sb->s_root = NULL;
+               iput(root);
                printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n");
                goto failed_mount4;
        }
+       sb->s_root = d_alloc_root(root);
+       if (!sb->s_root) {
+               printk(KERN_ERR "EXT3-fs: get root dentry failed\n");
+               iput(root);
+               ret = -ENOMEM;
+               goto failed_mount4;
+       }
 
        ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
        /*
@@ -1946,7 +1945,7 @@ out_fail:
        sb->s_fs_info = NULL;
        kfree(sbi);
        lock_kernel();
-       return -EINVAL;
+       return ret;
 }
 
 /*
@@ -1982,8 +1981,8 @@ static journal_t *ext3_get_journal(struct super_block *sb,
         * things happen if we iget() an unused inode, as the subsequent
         * iput() will try to delete it. */
 
-       journal_inode = iget(sb, journal_inum);
-       if (!journal_inode) {
+       journal_inode = ext3_iget(sb, journal_inum);
+       if (IS_ERR(journal_inode)) {
                printk(KERN_ERR "EXT3-fs: no journal found.\n");
                return NULL;
        }
@@ -1996,7 +1995,7 @@ static journal_t *ext3_get_journal(struct super_block *sb,
 
        jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
                  journal_inode, journal_inode->i_size);
-       if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
+       if (!S_ISREG(journal_inode->i_mode)) {
                printk(KERN_ERR "EXT3-fs: invalid journal inode.\n");
                iput(journal_inode);
                return NULL;
index ac75ea953d83fbfe3d3919783f85c963d905c264..0737e05ba3dd22842429f287356ca1c500265943 100644 (file)
@@ -1700,7 +1700,7 @@ retry_alloc:
 
        /*
         * Now search the rest of the groups.  We assume that
-        * i and gdp correctly point to the last group visited.
+        * group_no and gdp correctly point to the last group visited.
         */
        for (bgi = 0; bgi < ngroups; bgi++) {
                group_no++;
@@ -2011,11 +2011,7 @@ static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb,
 static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,
                                        ext4_group_t group)
 {
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
-                       !ext4_group_sparse(group))
-               return 0;
-       return EXT4_SB(sb)->s_gdb_count;
+       return ext4_bg_has_super(sb, group) ? EXT4_SB(sb)->s_gdb_count : 0;
 }
 
 /**
index 575b5215c8084f3613484555afb0f5727a404826..da18a74b966a91da09ae9710ba8976a111f3946f 100644 (file)
@@ -782,14 +782,15 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
        unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count);
        ext4_group_t block_group;
        int bit;
-       struct buffer_head *bitmap_bh = NULL;
+       struct buffer_head *bitmap_bh;
        struct inode *inode = NULL;
+       long err = -EIO;
 
        /* Error cases - e2fsck has already cleaned up for us */
        if (ino > max_ino) {
                ext4_warning(sb, __FUNCTION__,
                             "bad orphan ino %lu!  e2fsck was run?", ino);
-               goto out;
+               goto error;
        }
 
        block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
@@ -798,38 +799,49 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
        if (!bitmap_bh) {
                ext4_warning(sb, __FUNCTION__,
                             "inode bitmap error for orphan %lu", ino);
-               goto out;
+               goto error;
        }
 
        /* Having the inode bit set should be a 100% indicator that this
         * is a valid orphan (no e2fsck run on fs).  Orphans also include
         * inodes that were being truncated, so we can't check i_nlink==0.
         */
-       if (!ext4_test_bit(bit, bitmap_bh->b_data) ||
-                       !(inode = iget(sb, ino)) || is_bad_inode(inode) ||
-                       NEXT_ORPHAN(inode) > max_ino) {
-               ext4_warning(sb, __FUNCTION__,
-                            "bad orphan inode %lu!  e2fsck was run?", ino);
-               printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
-                      bit, (unsigned long long)bitmap_bh->b_blocknr,
-                      ext4_test_bit(bit, bitmap_bh->b_data));
-               printk(KERN_NOTICE "inode=%p\n", inode);
-               if (inode) {
-                       printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
-                              is_bad_inode(inode));
-                       printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
-                              NEXT_ORPHAN(inode));
-                       printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
-               }
+       if (!ext4_test_bit(bit, bitmap_bh->b_data))
+               goto bad_orphan;
+
+       inode = ext4_iget(sb, ino);
+       if (IS_ERR(inode))
+               goto iget_failed;
+
+       if (NEXT_ORPHAN(inode) > max_ino)
+               goto bad_orphan;
+       brelse(bitmap_bh);
+       return inode;
+
+iget_failed:
+       err = PTR_ERR(inode);
+       inode = NULL;
+bad_orphan:
+       ext4_warning(sb, __FUNCTION__,
+                    "bad orphan inode %lu!  e2fsck was run?", ino);
+       printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
+              bit, (unsigned long long)bitmap_bh->b_blocknr,
+              ext4_test_bit(bit, bitmap_bh->b_data));
+       printk(KERN_NOTICE "inode=%p\n", inode);
+       if (inode) {
+               printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
+                      is_bad_inode(inode));
+               printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
+                      NEXT_ORPHAN(inode));
+               printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
                /* Avoid freeing blocks if we got a bad deleted inode */
-               if (inode && inode->i_nlink == 0)
+               if (inode->i_nlink == 0)
                        inode->i_blocks = 0;
                iput(inode);
-               inode = NULL;
        }
-out:
        brelse(bitmap_bh);
-       return inode;
+error:
+       return ERR_PTR(err);
 }
 
 unsigned long ext4_count_free_inodes (struct super_block * sb)
index 05c4145dd27d3e03b634d7525aea9fe472012a58..f4e3874522465cb52324fa7d317dbc2a11e83fb4 100644 (file)
@@ -429,16 +429,13 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
  *     ext4_find_goal - find a prefered place for allocation.
  *     @inode: owner
  *     @block:  block we want
- *     @chain:  chain of indirect blocks
  *     @partial: pointer to the last triple within a chain
- *     @goal:  place to store the result.
  *
  *     Normally this function find the prefered place for block allocation,
- *     stores it in *@goal and returns zero.
+ *     returns it.
  */
-
 static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block,
-               Indirect chain[4], Indirect *partial)
+               Indirect *partial)
 {
        struct ext4_block_alloc_info *block_i;
 
@@ -839,7 +836,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
        if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
                ext4_init_block_alloc_info(inode);
 
-       goal = ext4_find_goal(inode, iblock, chain, partial);
+       goal = ext4_find_goal(inode, iblock, partial);
 
        /* the number of blocks need to allocate for [d,t]indirect blocks */
        indirect_blks = (chain + depth) - partial - 1;
@@ -2683,21 +2680,31 @@ static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode,
        }
 }
 
-void ext4_read_inode(struct inode * inode)
+struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
 {
        struct ext4_iloc iloc;
        struct ext4_inode *raw_inode;
-       struct ext4_inode_info *ei = EXT4_I(inode);
+       struct ext4_inode_info *ei;
        struct buffer_head *bh;
+       struct inode *inode;
+       long ret;
        int block;
 
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       ei = EXT4_I(inode);
 #ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
        ei->i_acl = EXT4_ACL_NOT_CACHED;
        ei->i_default_acl = EXT4_ACL_NOT_CACHED;
 #endif
        ei->i_block_alloc_info = NULL;
 
-       if (__ext4_get_inode_loc(inode, &iloc, 0))
+       ret = __ext4_get_inode_loc(inode, &iloc, 0);
+       if (ret < 0)
                goto bad_inode;
        bh = iloc.bh;
        raw_inode = ext4_raw_inode(&iloc);
@@ -2723,6 +2730,7 @@ void ext4_read_inode(struct inode * inode)
                    !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) {
                        /* this inode is deleted */
                        brelse (bh);
+                       ret = -ESTALE;
                        goto bad_inode;
                }
                /* The only unlinked inodes we let through here have
@@ -2761,6 +2769,7 @@ void ext4_read_inode(struct inode * inode)
                if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
                    EXT4_INODE_SIZE(inode->i_sb)) {
                        brelse (bh);
+                       ret = -EIO;
                        goto bad_inode;
                }
                if (ei->i_extra_isize == 0) {
@@ -2814,11 +2823,12 @@ void ext4_read_inode(struct inode * inode)
        }
        brelse (iloc.bh);
        ext4_set_inode_flags(inode);
-       return;
+       unlock_new_inode(inode);
+       return inode;
 
 bad_inode:
-       make_bad_inode(inode);
-       return;
+       iget_failed(inode);
+       return ERR_PTR(ret);
 }
 
 static int ext4_inode_blocks_set(handle_t *handle,
index 67b6d8a1ceff3423df8741ec426e640a8c3e8a2a..d153bb5922fc1dc79021e5ad84d5108d81702e74 100644 (file)
@@ -1039,17 +1039,11 @@ static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, str
                if (!ext4_valid_inum(dir->i_sb, ino)) {
                        ext4_error(dir->i_sb, "ext4_lookup",
                                   "bad inode number: %lu", ino);
-                       inode = NULL;
-               } else
-                       inode = iget(dir->i_sb, ino);
-
-               if (!inode)
-                       return ERR_PTR(-EACCES);
-
-               if (is_bad_inode(inode)) {
-                       iput(inode);
-                       return ERR_PTR(-ENOENT);
+                       return ERR_PTR(-EIO);
                }
+               inode = ext4_iget(dir->i_sb, ino);
+               if (IS_ERR(inode))
+                       return ERR_CAST(inode);
        }
        return d_splice_alias(inode, dentry);
 }
@@ -1078,18 +1072,13 @@ struct dentry *ext4_get_parent(struct dentry *child)
        if (!ext4_valid_inum(child->d_inode->i_sb, ino)) {
                ext4_error(child->d_inode->i_sb, "ext4_get_parent",
                           "bad inode number: %lu", ino);
-               inode = NULL;
-       } else
-               inode = iget(child->d_inode->i_sb, ino);
-
-       if (!inode)
-               return ERR_PTR(-EACCES);
-
-       if (is_bad_inode(inode)) {
-               iput(inode);
-               return ERR_PTR(-ENOENT);
+               return ERR_PTR(-EIO);
        }
 
+       inode = ext4_iget(child->d_inode->i_sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+
        parent = d_alloc_anon(inode);
        if (!parent) {
                iput(inode);
index 4fbba60816f461a2f08303ea306934f27ede641e..9477a2bd6ff2ea0c2ae9180c89a0166d470df1b6 100644 (file)
@@ -779,12 +779,11 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
                                     "No reserved GDT blocks, can't resize");
                        return -EPERM;
                }
-               inode = iget(sb, EXT4_RESIZE_INO);
-               if (!inode || is_bad_inode(inode)) {
+               inode = ext4_iget(sb, EXT4_RESIZE_INO);
+               if (IS_ERR(inode)) {
                        ext4_warning(sb, __FUNCTION__,
                                     "Error opening resize inode");
-                       iput(inode);
-                       return -ENOENT;
+                       return PTR_ERR(inode);
                }
        }
 
index 055a0cd0168e5029ee87bb3ce8c55153fae3b171..93beb865c20d30f129bac6fb1ed0d99fb699a485 100644 (file)
@@ -777,11 +777,10 @@ static struct inode *ext4_nfs_get_inode(struct super_block *sb,
         * Currently we don't know the generation for parent directory, so
         * a generation of 0 means "accept any"
         */
-       inode = iget(sb, ino);
-       if (inode == NULL)
-               return ERR_PTR(-ENOMEM);
-       if (is_bad_inode(inode) ||
-           (generation && inode->i_generation != generation)) {
+       inode = ext4_iget(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       if (generation && inode->i_generation != generation) {
                iput(inode);
                return ERR_PTR(-ESTALE);
        }
@@ -850,7 +849,6 @@ static struct quotactl_ops ext4_qctl_operations = {
 static const struct super_operations ext4_sops = {
        .alloc_inode    = ext4_alloc_inode,
        .destroy_inode  = ext4_destroy_inode,
-       .read_inode     = ext4_read_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
        .delete_inode   = ext4_delete_inode,
@@ -1458,7 +1456,7 @@ int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group,
 }
 
 /* Called at mount-time, super-block is locked */
-static int ext4_check_descriptors (struct super_block * sb)
+static int ext4_check_descriptors(struct super_block *sb)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
@@ -1466,8 +1464,6 @@ static int ext4_check_descriptors (struct super_block * sb)
        ext4_fsblk_t block_bitmap;
        ext4_fsblk_t inode_bitmap;
        ext4_fsblk_t inode_table;
-       struct ext4_group_desc * gdp = NULL;
-       int desc_block = 0;
        int flexbg_flag = 0;
        ext4_group_t i;
 
@@ -1476,17 +1472,15 @@ static int ext4_check_descriptors (struct super_block * sb)
 
        ext4_debug ("Checking group descriptors");
 
-       for (i = 0; i < sbi->s_groups_count; i++)
-       {
+       for (i = 0; i < sbi->s_groups_count; i++) {
+               struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
+
                if (i == sbi->s_groups_count - 1 || flexbg_flag)
                        last_block = ext4_blocks_count(sbi->s_es) - 1;
                else
                        last_block = first_block +
                                (EXT4_BLOCKS_PER_GROUP(sb) - 1);
 
-               if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0)
-                       gdp = (struct ext4_group_desc *)
-                                       sbi->s_group_desc[desc_block++]->b_data;
                block_bitmap = ext4_block_bitmap(sb, gdp);
                if (block_bitmap < first_block || block_bitmap > last_block)
                {
@@ -1524,8 +1518,6 @@ static int ext4_check_descriptors (struct super_block * sb)
                }
                if (!flexbg_flag)
                        first_block += EXT4_BLOCKS_PER_GROUP(sb);
-               gdp = (struct ext4_group_desc *)
-                       ((__u8 *)gdp + EXT4_DESC_SIZE(sb));
        }
 
        ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
@@ -1811,6 +1803,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
        unsigned long journal_devnum = 0;
        unsigned long def_mount_opts;
        struct inode *root;
+       int ret = -EINVAL;
        int blocksize;
        int db_count;
        int i;
@@ -2243,19 +2236,24 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
         * so we can safely mount the rest of the filesystem now.
         */
 
-       root = iget(sb, EXT4_ROOT_INO);
-       sb->s_root = d_alloc_root(root);
-       if (!sb->s_root) {
+       root = ext4_iget(sb, EXT4_ROOT_INO);
+       if (IS_ERR(root)) {
                printk(KERN_ERR "EXT4-fs: get root inode failed\n");
-               iput(root);
+               ret = PTR_ERR(root);
                goto failed_mount4;
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
-               dput(sb->s_root);
-               sb->s_root = NULL;
+               iput(root);
                printk(KERN_ERR "EXT4-fs: corrupt root inode, run e2fsck\n");
                goto failed_mount4;
        }
+       sb->s_root = d_alloc_root(root);
+       if (!sb->s_root) {
+               printk(KERN_ERR "EXT4-fs: get root dentry failed\n");
+               iput(root);
+               ret = -ENOMEM;
+               goto failed_mount4;
+       }
 
        ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);
 
@@ -2336,7 +2334,7 @@ out_fail:
        sb->s_fs_info = NULL;
        kfree(sbi);
        lock_kernel();
-       return -EINVAL;
+       return ret;
 }
 
 /*
@@ -2372,8 +2370,8 @@ static journal_t *ext4_get_journal(struct super_block *sb,
         * things happen if we iget() an unused inode, as the subsequent
         * iput() will try to delete it. */
 
-       journal_inode = iget(sb, journal_inum);
-       if (!journal_inode) {
+       journal_inode = ext4_iget(sb, journal_inum);
+       if (IS_ERR(journal_inode)) {
                printk(KERN_ERR "EXT4-fs: no journal found.\n");
                return NULL;
        }
@@ -2386,7 +2384,7 @@ static journal_t *ext4_get_journal(struct super_block *sb,
 
        jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
                  journal_inode, journal_inode->i_size);
-       if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
+       if (!S_ISREG(journal_inode->i_mode)) {
                printk(KERN_ERR "EXT4-fs: invalid journal inode.\n");
                iput(journal_inode);
                return NULL;
index 69a83b59dce80bdc84f1d4507e1ad74195c38690..c614175876e09316ea0a36566dc072fe6819169c 100644 (file)
@@ -155,6 +155,42 @@ out:
        return err;
 }
 
+static int check_mode(const struct msdos_sb_info *sbi, mode_t mode)
+{
+       mode_t req = mode & ~S_IFMT;
+
+       /*
+        * Of the r and x bits, all (subject to umask) must be present. Of the
+        * w bits, either all (subject to umask) or none must be present.
+        */
+
+       if (S_ISREG(mode)) {
+               req &= ~sbi->options.fs_fmask;
+
+               if ((req & (S_IRUGO | S_IXUGO)) !=
+                   ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask))
+                       return -EPERM;
+
+               if ((req & S_IWUGO) != 0 &&
+                   (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask))
+                       return -EPERM;
+       } else if (S_ISDIR(mode)) {
+               req &= ~sbi->options.fs_dmask;
+
+               if ((req & (S_IRUGO | S_IXUGO)) !=
+                   ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask))
+                       return -EPERM;
+
+               if ((req & S_IWUGO) != 0 &&
+                   (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask))
+                       return -EPERM;
+       } else {
+               return -EPERM;
+       }
+
+       return 0;
+}
+
 int fat_notify_change(struct dentry *dentry, struct iattr *attr)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
@@ -186,9 +222,7 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
        if (((attr->ia_valid & ATTR_UID) &&
             (attr->ia_uid != sbi->options.fs_uid)) ||
            ((attr->ia_valid & ATTR_GID) &&
-            (attr->ia_gid != sbi->options.fs_gid)) ||
-           ((attr->ia_valid & ATTR_MODE) &&
-            (attr->ia_mode & ~MSDOS_VALID_MODE)))
+            (attr->ia_gid != sbi->options.fs_gid)))
                error = -EPERM;
 
        if (error) {
@@ -196,6 +230,13 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
                        error = 0;
                goto out;
        }
+
+       if (attr->ia_valid & ATTR_MODE) {
+               error = check_mode(sbi, attr->ia_mode);
+               if (error != 0 && !sbi->options.quiet)
+                       goto out;
+       }
+
        error = inode_setattr(inode, attr);
        if (error)
                goto out;
index 920a576e1c25e26240c8ed583cbdfce7e4452e4e..085269e07fb3a86f9849b54d5403f68de5bed844 100644 (file)
@@ -634,8 +634,6 @@ static const struct super_operations fat_sops = {
        .clear_inode    = fat_clear_inode,
        .remount_fs     = fat_remount,
 
-       .read_inode     = make_bad_inode,
-
        .show_options   = fat_show_options,
 };
 
@@ -663,8 +661,8 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb,
        if (fh_len < 5 || fh_type != 3)
                return NULL;
 
-       inode = iget(sb, fh[0]);
-       if (!inode || is_bad_inode(inode) || inode->i_generation != fh[1]) {
+       inode = ilookup(sb, fh[0]);
+       if (!inode || inode->i_generation != fh[1]) {
                if (inode)
                        iput(inode);
                inode = NULL;
@@ -760,7 +758,7 @@ static struct dentry *fat_get_parent(struct dentry *child)
        inode = fat_build_inode(child->d_sb, de, i_pos);
        brelse(bh);
        if (IS_ERR(inode)) {
-               parent = ERR_PTR(PTR_ERR(inode));
+               parent = ERR_CAST(inode);
                goto out;
        }
        parent = d_alloc_anon(inode);
@@ -1295,10 +1293,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
 
                fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data;
                if (!IS_FSINFO(fsinfo)) {
-                       printk(KERN_WARNING
-                              "FAT: Did not find valid FSINFO signature.\n"
-                              "     Found signature1 0x%08x signature2 0x%08x"
-                              " (sector = %lu)\n",
+                       printk(KERN_WARNING "FAT: Invalid FSINFO signature: "
+                              "0x%08x, 0x%08x (sector = %lu)\n",
                               le32_to_cpu(fsinfo->signature1),
                               le32_to_cpu(fsinfo->signature2),
                               sbi->fsinfo_sector);
index 308f2b6b50264da37c24843a1943d1e5ad22bc4e..61f23511eacf41ec34649a84f1cc7e601ff61a68 100644 (file)
@@ -55,9 +55,8 @@ void fat_clusters_flush(struct super_block *sb)
        fsinfo = (struct fat_boot_fsinfo *)bh->b_data;
        /* Sanity check */
        if (!IS_FSINFO(fsinfo)) {
-               printk(KERN_ERR "FAT: Did not find valid FSINFO signature.\n"
-                      "     Found signature1 0x%08x signature2 0x%08x"
-                      " (sector = %lu)\n",
+               printk(KERN_ERR "FAT: Invalid FSINFO signature: "
+                      "0x%08x, 0x%08x (sector = %lu)\n",
                       le32_to_cpu(fsinfo->signature1),
                       le32_to_cpu(fsinfo->signature2),
                       sbi->fsinfo_sector);
index c5575de01113eb24aa182c77b35d46d0f0fced48..5110acb1c9ef59bb046a69f79fa601a07218b61a 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -24,6 +24,8 @@ struct fdtable_defer {
        struct fdtable *next;
 };
 
+int sysctl_nr_open __read_mostly = 1024*1024;
+
 /*
  * We use this list to defer free fdtables that have vmalloced
  * sets/arrays. By keeping a per-cpu list, we avoid having to embed
@@ -147,8 +149,8 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
        nr /= (1024 / sizeof(struct file *));
        nr = roundup_pow_of_two(nr + 1);
        nr *= (1024 / sizeof(struct file *));
-       if (nr > NR_OPEN)
-               nr = NR_OPEN;
+       if (nr > sysctl_nr_open)
+               nr = sysctl_nr_open;
 
        fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
        if (!fdt)
@@ -233,7 +235,7 @@ int expand_files(struct files_struct *files, int nr)
        if (nr < fdt->max_fds)
                return 0;
        /* Can we expand? */
-       if (nr >= NR_OPEN)
+       if (nr >= sysctl_nr_open)
                return -EMFILE;
 
        /* All good, so we try */
index 91ccee8723f7cdd9cbacb3f3a070624e2053ca20..2b46064f66b2ed1a393ef9729253f59d90115c06 100644 (file)
@@ -58,7 +58,7 @@ extern struct inode *         vxfs_get_fake_inode(struct super_block *,
 extern void                    vxfs_put_fake_inode(struct inode *);
 extern struct vxfs_inode_info *        vxfs_blkiget(struct super_block *, u_long, ino_t);
 extern struct vxfs_inode_info *        vxfs_stiget(struct super_block *, ino_t);
-extern void                    vxfs_read_inode(struct inode *);
+extern struct inode *          vxfs_iget(struct super_block *, ino_t);
 extern void                    vxfs_clear_inode(struct inode *);
 
 /* vxfs_lookup.c */
index d1f7c5b5b3c350d0656a4f33b7d841b4f450e1b3..ad88d2364bc258bc2d1b07283304d935eeab3369 100644 (file)
@@ -129,7 +129,7 @@ fail:
  * Description:
  *  Search the for inode number @ino in the filesystem
  *  described by @sbp.  Use the specified inode table (@ilistp).
- *  Returns the matching VxFS inode on success, else a NULL pointer.
+ *  Returns the matching VxFS inode on success, else an error code.
  */
 static struct vxfs_inode_info *
 __vxfs_iget(ino_t ino, struct inode *ilistp)
@@ -157,12 +157,12 @@ __vxfs_iget(ino_t ino, struct inode *ilistp)
        }
 
        printk(KERN_WARNING "vxfs: error on page %p\n", pp);
-       return NULL;
+       return ERR_CAST(pp);
 
 fail:
        printk(KERN_WARNING "vxfs: unable to read inode %ld\n", (unsigned long)ino);
        vxfs_put_page(pp);
-       return NULL;
+       return ERR_PTR(-ENOMEM);
 }
 
 /**
@@ -178,7 +178,10 @@ fail:
 struct vxfs_inode_info *
 vxfs_stiget(struct super_block *sbp, ino_t ino)
 {
-        return __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
+       struct vxfs_inode_info *vip;
+
+       vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
+       return IS_ERR(vip) ? NULL : vip;
 }
 
 /**
@@ -282,23 +285,32 @@ vxfs_put_fake_inode(struct inode *ip)
 }
 
 /**
- * vxfs_read_inode - fill in inode information
- * @ip:                inode pointer to fill
+ * vxfs_iget - get an inode
+ * @sbp:       the superblock to get the inode for
+ * @ino:       the number of the inode to get
  *
  * Description:
- *  vxfs_read_inode reads the disk inode for @ip and fills
- *  in all relevant fields in @ip.
+ *  vxfs_read_inode creates an inode, reads the disk inode for @ino and fills
+ *  in all relevant fields in the new inode.
  */
-void
-vxfs_read_inode(struct inode *ip)
+struct inode *
+vxfs_iget(struct super_block *sbp, ino_t ino)
 {
-       struct super_block              *sbp = ip->i_sb;
        struct vxfs_inode_info          *vip;
        const struct address_space_operations   *aops;
-       ino_t                           ino = ip->i_ino;
-
-       if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist)))
-               return;
+       struct inode *ip;
+
+       ip = iget_locked(sbp, ino);
+       if (!ip)
+               return ERR_PTR(-ENOMEM);
+       if (!(ip->i_state & I_NEW))
+               return ip;
+
+       vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist);
+       if (IS_ERR(vip)) {
+               iget_failed(ip);
+               return ERR_CAST(vip);
+       }
 
        vxfs_iinit(ip, vip);
 
@@ -323,7 +335,8 @@ vxfs_read_inode(struct inode *ip)
        } else
                init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev));
 
-       return;
+       unlock_new_inode(ip);
+       return ip;
 }
 
 /**
index bf86e5444ea6d705a99682b83987b586a40a1e04..aee049cb9f84782640d365a90156f423d2a37b46 100644 (file)
@@ -213,10 +213,10 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
        lock_kernel();
        ino = vxfs_inode_by_name(dip, dp);
        if (ino) {
-               ip = iget(dip->i_sb, ino);
-               if (!ip) {
+               ip = vxfs_iget(dip->i_sb, ino);
+               if (IS_ERR(ip)) {
                        unlock_kernel();
-                       return ERR_PTR(-EACCES);
+                       return ERR_CAST(ip);
                }
        }
        unlock_kernel();
index 4f95572d2722d047d0e7e1ac3307ca47bf6122e4..1dacda8315775d79f358558234ec4f6a5daf1d76 100644 (file)
@@ -60,7 +60,6 @@ static int            vxfs_statfs(struct dentry *, struct kstatfs *);
 static int             vxfs_remount(struct super_block *, int *, char *);
 
 static const struct super_operations vxfs_super_ops = {
-       .read_inode =           vxfs_read_inode,
        .clear_inode =          vxfs_clear_inode,
        .put_super =            vxfs_put_super,
        .statfs =               vxfs_statfs,
@@ -153,6 +152,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
        struct buffer_head      *bp = NULL;
        u_long                  bsize;
        struct inode *root;
+       int ret = -EINVAL;
 
        sbp->s_flags |= MS_RDONLY;
 
@@ -219,7 +219,11 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
        }
 
        sbp->s_op = &vxfs_super_ops;
-       root = iget(sbp, VXFS_ROOT_INO);
+       root = vxfs_iget(sbp, VXFS_ROOT_INO);
+       if (IS_ERR(root)) {
+               ret = PTR_ERR(root);
+               goto out;
+       }
        sbp->s_root = d_alloc_root(root);
        if (!sbp->s_root) {
                iput(root);
@@ -236,7 +240,7 @@ out_free_ilist:
 out:
        brelse(bp);
        kfree(infp);
-       return -EINVAL;
+       return ret;
 }
 
 /*
index 0b3064079fa530e9c6d68739d931cff50af069a3..db80ce9eb1d07896fb3ddd5f545ed8876dc8b2fa 100644 (file)
@@ -515,8 +515,7 @@ writeback_inodes(struct writeback_control *wbc)
        might_sleep();
        spin_lock(&sb_lock);
 restart:
-       sb = sb_entry(super_blocks.prev);
-       for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
+       list_for_each_entry_reverse(sb, &super_blocks, s_list) {
                if (sb_has_dirty_inodes(sb)) {
                        /* we're making our own get_super here */
                        sb->s_count++;
@@ -581,10 +580,8 @@ static void set_sb_syncing(int val)
 {
        struct super_block *sb;
        spin_lock(&sb_lock);
-       sb = sb_entry(super_blocks.prev);
-       for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
+       list_for_each_entry_reverse(sb, &super_blocks, s_list)
                sb->s_syncing = val;
-       }
        spin_unlock(&sb_lock);
 }
 
index db534bcde45f6ff52a7cbfb44fcb8b49ea9bbb9d..af639807524e63164397b32f8589bf75131a5112 100644 (file)
@@ -201,6 +201,55 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
        }
 }
 
+static unsigned len_args(unsigned numargs, struct fuse_arg *args)
+{
+       unsigned nbytes = 0;
+       unsigned i;
+
+       for (i = 0; i < numargs; i++)
+               nbytes += args[i].size;
+
+       return nbytes;
+}
+
+static u64 fuse_get_unique(struct fuse_conn *fc)
+{
+       fc->reqctr++;
+       /* zero is special */
+       if (fc->reqctr == 0)
+               fc->reqctr = 1;
+
+       return fc->reqctr;
+}
+
+static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
+{
+       req->in.h.unique = fuse_get_unique(fc);
+       req->in.h.len = sizeof(struct fuse_in_header) +
+               len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
+       list_add_tail(&req->list, &fc->pending);
+       req->state = FUSE_REQ_PENDING;
+       if (!req->waiting) {
+               req->waiting = 1;
+               atomic_inc(&fc->num_waiting);
+       }
+       wake_up(&fc->waitq);
+       kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+}
+
+static void flush_bg_queue(struct fuse_conn *fc)
+{
+       while (fc->active_background < FUSE_MAX_BACKGROUND &&
+              !list_empty(&fc->bg_queue)) {
+               struct fuse_req *req;
+
+               req = list_entry(fc->bg_queue.next, struct fuse_req, list);
+               list_del(&req->list);
+               fc->active_background++;
+               queue_request(fc, req);
+       }
+}
+
 /*
  * This function is called when a request is finished.  Either a reply
  * has arrived or it was aborted (and not yet sent) or some error
@@ -229,6 +278,8 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
                        clear_bdi_congested(&fc->bdi, WRITE);
                }
                fc->num_background--;
+               fc->active_background--;
+               flush_bg_queue(fc);
        }
        spin_unlock(&fc->lock);
        wake_up(&req->waitq);
@@ -320,42 +371,6 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
        }
 }
 
-static unsigned len_args(unsigned numargs, struct fuse_arg *args)
-{
-       unsigned nbytes = 0;
-       unsigned i;
-
-       for (i = 0; i < numargs; i++)
-               nbytes += args[i].size;
-
-       return nbytes;
-}
-
-static u64 fuse_get_unique(struct fuse_conn *fc)
- {
-       fc->reqctr++;
-       /* zero is special */
-       if (fc->reqctr == 0)
-               fc->reqctr = 1;
-
-       return fc->reqctr;
-}
-
-static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
-{
-       req->in.h.unique = fuse_get_unique(fc);
-       req->in.h.len = sizeof(struct fuse_in_header) +
-               len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
-       list_add_tail(&req->list, &fc->pending);
-       req->state = FUSE_REQ_PENDING;
-       if (!req->waiting) {
-               req->waiting = 1;
-               atomic_inc(&fc->num_waiting);
-       }
-       wake_up(&fc->waitq);
-       kill_fasync(&fc->fasync, SIGIO, POLL_IN);
-}
-
 void request_send(struct fuse_conn *fc, struct fuse_req *req)
 {
        req->isreply = 1;
@@ -375,20 +390,26 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req)
        spin_unlock(&fc->lock);
 }
 
+static void request_send_nowait_locked(struct fuse_conn *fc,
+                                      struct fuse_req *req)
+{
+       req->background = 1;
+       fc->num_background++;
+       if (fc->num_background == FUSE_MAX_BACKGROUND)
+               fc->blocked = 1;
+       if (fc->num_background == FUSE_CONGESTION_THRESHOLD) {
+               set_bdi_congested(&fc->bdi, READ);
+               set_bdi_congested(&fc->bdi, WRITE);
+       }
+       list_add_tail(&req->list, &fc->bg_queue);
+       flush_bg_queue(fc);
+}
+
 static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
 {
        spin_lock(&fc->lock);
        if (fc->connected) {
-               req->background = 1;
-               fc->num_background++;
-               if (fc->num_background == FUSE_MAX_BACKGROUND)
-                       fc->blocked = 1;
-               if (fc->num_background == FUSE_CONGESTION_THRESHOLD) {
-                       set_bdi_congested(&fc->bdi, READ);
-                       set_bdi_congested(&fc->bdi, WRITE);
-               }
-
-               queue_request(fc, req);
+               request_send_nowait_locked(fc, req);
                spin_unlock(&fc->lock);
        } else {
                req->out.h.error = -ENOTCONN;
index 80d2f5292cf91f490532e903c0e37795e705de15..7fb514b6d85294cfb76fe3fc94c681b6292834c4 100644 (file)
@@ -269,12 +269,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
 
        req = fuse_get_req(fc);
        if (IS_ERR(req))
-               return ERR_PTR(PTR_ERR(req));
+               return ERR_CAST(req);
 
        forget_req = fuse_get_req(fc);
        if (IS_ERR(forget_req)) {
                fuse_put_request(fc, req);
-               return ERR_PTR(PTR_ERR(forget_req));
+               return ERR_CAST(forget_req);
        }
 
        attr_version = fuse_get_attr_version(fc);
@@ -416,6 +416,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        fuse_put_request(fc, forget_req);
        d_instantiate(entry, inode);
        fuse_change_entry_timeout(entry, &outentry);
+       fuse_invalidate_attr(dir);
        file = lookup_instantiate_filp(nd, entry, generic_file_open);
        if (IS_ERR(file)) {
                ff->fh = outopen.fh;
@@ -1005,7 +1006,7 @@ static char *read_link(struct dentry *dentry)
        char *link;
 
        if (IS_ERR(req))
-               return ERR_PTR(PTR_ERR(req));
+               return ERR_CAST(req);
 
        link = (char *) __get_free_page(GFP_KERNEL);
        if (!link) {
index bb05d227cf30bb074da715a08d438e295fbc8892..676b0bc8a86dba3e3c048a1a35320d3931a65f20 100644 (file)
@@ -77,8 +77,8 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff)
 
 static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-       dput(req->dentry);
-       mntput(req->vfsmount);
+       dput(req->misc.release.dentry);
+       mntput(req->misc.release.vfsmount);
        fuse_put_request(fc, req);
 }
 
@@ -86,7 +86,8 @@ static void fuse_file_put(struct fuse_file *ff)
 {
        if (atomic_dec_and_test(&ff->count)) {
                struct fuse_req *req = ff->reserved_req;
-               struct fuse_conn *fc = get_fuse_conn(req->dentry->d_inode);
+               struct inode *inode = req->misc.release.dentry->d_inode;
+               struct fuse_conn *fc = get_fuse_conn(inode);
                req->end = fuse_release_end;
                request_send_background(fc, req);
                kfree(ff);
@@ -137,7 +138,7 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
 void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode)
 {
        struct fuse_req *req = ff->reserved_req;
-       struct fuse_release_in *inarg = &req->misc.release_in;
+       struct fuse_release_in *inarg = &req->misc.release.in;
 
        inarg->fh = ff->fh;
        inarg->flags = flags;
@@ -153,13 +154,14 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir)
        struct fuse_file *ff = file->private_data;
        if (ff) {
                struct fuse_conn *fc = get_fuse_conn(inode);
+               struct fuse_req *req = ff->reserved_req;
 
                fuse_release_fill(ff, get_node_id(inode), file->f_flags,
                                  isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
 
                /* Hold vfsmount and dentry until release is finished */
-               ff->reserved_req->vfsmount = mntget(file->f_path.mnt);
-               ff->reserved_req->dentry = dget(file->f_path.dentry);
+               req->misc.release.vfsmount = mntget(file->f_path.mnt);
+               req->misc.release.dentry = dget(file->f_path.dentry);
 
                spin_lock(&fc->lock);
                list_del(&ff->write_entry);
index 3ab8a3048e8b8fa185028cdeab329463ed6b1245..67aaf6ee38eaaeb1fedd9c313a160f623d58b8c3 100644 (file)
@@ -215,7 +215,11 @@ struct fuse_req {
        /** Data for asynchronous requests */
        union {
                struct fuse_forget_in forget_in;
-               struct fuse_release_in release_in;
+               struct {
+                       struct fuse_release_in in;
+                       struct vfsmount *vfsmount;
+                       struct dentry *dentry;
+               } release;
                struct fuse_init_in init_in;
                struct fuse_init_out init_out;
                struct fuse_read_in read_in;
@@ -238,12 +242,6 @@ struct fuse_req {
        /** File used in the request (or NULL) */
        struct fuse_file *ff;
 
-       /** vfsmount used in release */
-       struct vfsmount *vfsmount;
-
-       /** dentry used in release */
-       struct dentry *dentry;
-
        /** Request completion callback */
        void (*end)(struct fuse_conn *, struct fuse_req *);
 
@@ -298,6 +296,12 @@ struct fuse_conn {
        /** Number of requests currently in the background */
        unsigned num_background;
 
+       /** Number of background requests currently queued for userspace */
+       unsigned active_background;
+
+       /** The list of background requests set aside for later queuing */
+       struct list_head bg_queue;
+
        /** Pending interrupts */
        struct list_head interrupts;
 
index e5e80d1a46870dda75135efca29c793860164b15..574707409bbfafc92d91006fd74d065085170d43 100644 (file)
@@ -76,11 +76,6 @@ static void fuse_destroy_inode(struct inode *inode)
        kmem_cache_free(fuse_inode_cachep, inode);
 }
 
-static void fuse_read_inode(struct inode *inode)
-{
-       /* No op */
-}
-
 void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
                      unsigned long nodeid, u64 nlookup)
 {
@@ -465,6 +460,7 @@ static struct fuse_conn *new_conn(void)
                INIT_LIST_HEAD(&fc->processing);
                INIT_LIST_HEAD(&fc->io);
                INIT_LIST_HEAD(&fc->interrupts);
+               INIT_LIST_HEAD(&fc->bg_queue);
                atomic_set(&fc->num_waiting, 0);
                fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
                fc->bdi.unplug_io_fn = default_unplug_io_fn;
@@ -514,7 +510,6 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
 static const struct super_operations fuse_super_operations = {
        .alloc_inode    = fuse_alloc_inode,
        .destroy_inode  = fuse_destroy_inode,
-       .read_inode     = fuse_read_inode,
        .clear_inode    = fuse_clear_inode,
        .drop_inode     = generic_delete_inode,
        .remount_fs     = fuse_remount_fs,
index 57e2ed932adc1d910120d7d6c618210dfb20141f..c34709512b19053088b79bab935a8a93d2374ae4 100644 (file)
@@ -1498,7 +1498,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name)
        dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
        if (dent) {
                if (IS_ERR(dent))
-                       return ERR_PTR(PTR_ERR(dent));
+                       return ERR_CAST(dent);
                inode = gfs2_inode_lookup(dir->i_sb, 
                                be16_to_cpu(dent->de_type),
                                be64_to_cpu(dent->de_inum.no_addr),
index 80e09c50590a52ed1a6e77c47ea59459da4b1bde..7175a4d064356f6f36860ea57d24feed1acb3d0e 100644 (file)
@@ -334,7 +334,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
        gl->gl_state = LM_ST_UNLOCKED;
        gl->gl_demote_state = LM_ST_EXCLUSIVE;
        gl->gl_hash = hash;
-       gl->gl_owner_pid = 0;
+       gl->gl_owner_pid = NULL;
        gl->gl_ip = 0;
        gl->gl_ops = glops;
        gl->gl_req_gh = NULL;
@@ -399,7 +399,7 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
        INIT_LIST_HEAD(&gh->gh_list);
        gh->gh_gl = gl;
        gh->gh_ip = (unsigned long)__builtin_return_address(0);
-       gh->gh_owner_pid = current->pid;
+       gh->gh_owner_pid = get_pid(task_pid(current));
        gh->gh_state = state;
        gh->gh_flags = flags;
        gh->gh_error = 0;
@@ -433,6 +433,7 @@ void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *
 
 void gfs2_holder_uninit(struct gfs2_holder *gh)
 {
+       put_pid(gh->gh_owner_pid);
        gfs2_glock_put(gh->gh_gl);
        gh->gh_gl = NULL;
        gh->gh_ip = 0;
@@ -631,7 +632,7 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
                wait_on_holder(&gh);
                gfs2_holder_uninit(&gh);
        } else {
-               gl->gl_owner_pid = current->pid;
+               gl->gl_owner_pid = get_pid(task_pid(current));
                gl->gl_ip = (unsigned long)__builtin_return_address(0);
                spin_unlock(&gl->gl_spin);
        }
@@ -652,7 +653,7 @@ static int gfs2_glmutex_trylock(struct gfs2_glock *gl)
        if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
                acquired = 0;
        } else {
-               gl->gl_owner_pid = current->pid;
+               gl->gl_owner_pid = get_pid(task_pid(current));
                gl->gl_ip = (unsigned long)__builtin_return_address(0);
        }
        spin_unlock(&gl->gl_spin);
@@ -668,12 +669,17 @@ static int gfs2_glmutex_trylock(struct gfs2_glock *gl)
 
 static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
 {
+       struct pid *pid;
+
        spin_lock(&gl->gl_spin);
        clear_bit(GLF_LOCK, &gl->gl_flags);
-       gl->gl_owner_pid = 0;
+       pid = gl->gl_owner_pid;
+       gl->gl_owner_pid = NULL;
        gl->gl_ip = 0;
        run_queue(gl);
        spin_unlock(&gl->gl_spin);
+
+       put_pid(pid);
 }
 
 /**
@@ -1045,7 +1051,7 @@ static int glock_wait_internal(struct gfs2_holder *gh)
 }
 
 static inline struct gfs2_holder *
-find_holder_by_owner(struct list_head *head, pid_t pid)
+find_holder_by_owner(struct list_head *head, struct pid *pid)
 {
        struct gfs2_holder *gh;
 
@@ -1082,7 +1088,7 @@ static void add_to_queue(struct gfs2_holder *gh)
        struct gfs2_glock *gl = gh->gh_gl;
        struct gfs2_holder *existing;
 
-       BUG_ON(!gh->gh_owner_pid);
+       BUG_ON(gh->gh_owner_pid == NULL);
        if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
                BUG();
 
@@ -1092,12 +1098,14 @@ static void add_to_queue(struct gfs2_holder *gh)
                if (existing) {
                        print_symbol(KERN_WARNING "original: %s\n", 
                                     existing->gh_ip);
-                       printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
+                       printk(KERN_INFO "pid : %d\n",
+                                       pid_nr(existing->gh_owner_pid));
                        printk(KERN_INFO "lock type : %d lock state : %d\n",
                               existing->gh_gl->gl_name.ln_type, 
                               existing->gh_gl->gl_state);
                        print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
-                       printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
+                       printk(KERN_INFO "pid : %d\n",
+                                       pid_nr(gh->gh_owner_pid));
                        printk(KERN_INFO "lock type : %d lock state : %d\n",
                               gl->gl_name.ln_type, gl->gl_state);
                        BUG();
@@ -1798,8 +1806,9 @@ static int dump_holder(struct glock_iter *gi, char *str,
 
        print_dbg(gi, "  %s\n", str);
        if (gh->gh_owner_pid) {
-               print_dbg(gi, "    owner = %ld ", (long)gh->gh_owner_pid);
-               gh_owner = find_task_by_pid(gh->gh_owner_pid);
+               print_dbg(gi, "    owner = %ld ",
+                               (long)pid_nr(gh->gh_owner_pid));
+               gh_owner = pid_task(gh->gh_owner_pid, PIDTYPE_PID);
                if (gh_owner)
                        print_dbg(gi, "(%s)\n", gh_owner->comm);
                else
@@ -1877,13 +1886,13 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
        print_dbg(gi, "  gl_ref = %d\n", atomic_read(&gl->gl_ref));
        print_dbg(gi, "  gl_state = %u\n", gl->gl_state);
        if (gl->gl_owner_pid) {
-               gl_owner = find_task_by_pid(gl->gl_owner_pid);
+               gl_owner = pid_task(gl->gl_owner_pid, PIDTYPE_PID);
                if (gl_owner)
                        print_dbg(gi, "  gl_owner = pid %d (%s)\n",
-                                 gl->gl_owner_pid, gl_owner->comm);
+                                 pid_nr(gl->gl_owner_pid), gl_owner->comm);
                else
                        print_dbg(gi, "  gl_owner = %d (ended)\n",
-                                 gl->gl_owner_pid);
+                                 pid_nr(gl->gl_owner_pid));
        } else
                print_dbg(gi, "  gl_owner = -1\n");
        print_dbg(gi, "  gl_ip = %lu\n", gl->gl_ip);
index b16f604eea9fd6e052ac29b17766f16ad2316adb..2f9c6d136b37a860a790367a35e02c2e59d47130 100644 (file)
@@ -36,11 +36,13 @@ static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl)
 {
        struct gfs2_holder *gh;
        int locked = 0;
+       struct pid *pid;
 
        /* Look in glock's list of holders for one with current task as owner */
        spin_lock(&gl->gl_spin);
+       pid = task_pid(current);
        list_for_each_entry(gh, &gl->gl_holders, gh_list) {
-               if (gh->gh_owner_pid == current->pid) {
+               if (gh->gh_owner_pid == pid) {
                        locked = 1;
                        break;
                }
index 513aaf0dc0ab5b6bbba7d10e9567d40cf33515c7..525dcae352d6b53bae1e2c464c488429c39b69a0 100644 (file)
@@ -151,7 +151,7 @@ struct gfs2_holder {
        struct list_head gh_list;
 
        struct gfs2_glock *gh_gl;
-       pid_t gh_owner_pid;
+       struct pid *gh_owner_pid;
        unsigned int gh_state;
        unsigned gh_flags;
 
@@ -182,7 +182,7 @@ struct gfs2_glock {
        unsigned int gl_hash;
        unsigned int gl_demote_state; /* state requested by remote node */
        unsigned long gl_demote_time; /* time of first demote request */
-       pid_t gl_owner_pid;
+       struct pid *gl_owner_pid;
        unsigned long gl_ip;
        struct list_head gl_holders;
        struct list_head gl_waiters1;   /* HIF_MUTEX */
index 728d3169e7bd5b32b112bf29852d52c394ef6915..37725ade3c51e38876cc796f30cc2e356b2248c4 100644 (file)
@@ -240,7 +240,7 @@ fail_put:
        ip->i_gl->gl_object = NULL;
        gfs2_glock_put(ip->i_gl);
 fail:
-       iput(inode);
+       iget_failed(inode);
        return ERR_PTR(error);
 }
 
index b9da62348a877303a777884c35f08c2083e640d5..334c7f85351bcd5397c7749aa009d56ed4e6608b 100644 (file)
@@ -143,7 +143,7 @@ static struct dentry *gfs2_get_parent(struct dentry *child)
         * have to return that as a(n invalid) pointer to dentry.
         */
        if (IS_ERR(inode))
-               return ERR_PTR(PTR_ERR(inode));
+               return ERR_CAST(inode);
 
        dentry = d_alloc_anon(inode);
        if (!dentry) {
index 9f71372c1757b04f17c0295b01a4a6fc17398cde..e87412902bed76313428bdeb7d7c3e9e1f476d59 100644 (file)
@@ -111,7 +111,7 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
 
        inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
        if (inode && IS_ERR(inode))
-               return ERR_PTR(PTR_ERR(inode));
+               return ERR_CAST(inode);
 
        if (inode) {
                struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
index f8452a0eab562085ddd50e3f3e52352bebcc4cb2..4129cdb3f0d8fbf80c4b161d877d9e922666f9ea 100644 (file)
@@ -52,9 +52,9 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
                rec = (e + b) / 2;
                len = hfs_brec_lenoff(bnode, rec, &off);
                keylen = hfs_brec_keylen(bnode, rec);
-               if (keylen == HFS_BAD_KEYLEN) {
+               if (keylen == 0) {
                        res = -EINVAL;
-                       goto done;
+                       goto fail;
                }
                hfs_bnode_read(bnode, fd->key, off, keylen);
                cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
@@ -71,9 +71,9 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
        if (rec != e && e >= 0) {
                len = hfs_brec_lenoff(bnode, e, &off);
                keylen = hfs_brec_keylen(bnode, e);
-               if (keylen == HFS_BAD_KEYLEN) {
+               if (keylen == 0) {
                        res = -EINVAL;
-                       goto done;
+                       goto fail;
                }
                hfs_bnode_read(bnode, fd->key, off, keylen);
        }
@@ -83,6 +83,7 @@ done:
        fd->keylength = keylen;
        fd->entryoffset = off + keylen;
        fd->entrylength = len - keylen;
+fail:
        return res;
 }
 
@@ -206,7 +207,7 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
 
        len = hfs_brec_lenoff(bnode, fd->record, &off);
        keylen = hfs_brec_keylen(bnode, fd->record);
-       if (keylen == HFS_BAD_KEYLEN) {
+       if (keylen == 0) {
                res = -EINVAL;
                goto out;
        }
index 8626ee375ea811d3a4e794a5f72a05d96b09bea0..878bf25dbc6a8c60d8ffc9736c0d6bf5c20ed699 100644 (file)
@@ -49,14 +49,14 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
                        if (retval > node->tree->max_key_len + 2) {
                                printk(KERN_ERR "hfs: keylen %d too large\n",
                                        retval);
-                               retval = HFS_BAD_KEYLEN;
+                               retval = 0;
                        }
                } else {
                        retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
                        if (retval > node->tree->max_key_len + 1) {
                                printk(KERN_ERR "hfs: keylen %d too large\n",
                                        retval);
-                               retval = HFS_BAD_KEYLEN;
+                               retval = 0;
                        }
                }
        }
index 110dd3515dc89b27e226a9a65867f338df18de69..24cf6fc4302122366ed444c7f5f3344b7cae7382 100644 (file)
@@ -81,15 +81,23 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
                goto fail_page;
        if (!tree->node_count)
                goto fail_page;
-       if ((id == HFS_EXT_CNID) && (tree->max_key_len != HFS_MAX_EXT_KEYLEN)) {
-               printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
-                       tree->max_key_len);
-               goto fail_page;
-       }
-       if ((id == HFS_CAT_CNID) && (tree->max_key_len != HFS_MAX_CAT_KEYLEN)) {
-               printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
-                       tree->max_key_len);
-               goto fail_page;
+       switch (id) {
+       case HFS_EXT_CNID:
+               if (tree->max_key_len != HFS_MAX_EXT_KEYLEN) {
+                       printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
+                               tree->max_key_len);
+                       goto fail_page;
+               }
+               break;
+       case HFS_CAT_CNID:
+               if (tree->max_key_len != HFS_MAX_CAT_KEYLEN) {
+                       printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
+                               tree->max_key_len);
+                       goto fail_page;
+               }
+               break;
+       default:
+               BUG();
        }
 
        tree->node_size_shift = ffs(size) - 1;
index c6aae61adfe6f098f9c0fc260b1090b1331d29d9..6f194d0768b6fd72b76e617ffc7711b0edd25982 100644 (file)
@@ -28,8 +28,6 @@
 #define HFS_MAX_NAMELEN                128
 #define HFS_MAX_VALENCE                32767U
 
-#define HFS_BAD_KEYLEN         0xFF
-
 /* Meanings of the drAtrb field of the MDB,
  * Reference: _Inside Macintosh: Files_ p. 2-61
  */
index 16cbd902f8b9569a6874710832d7ab1316010063..32de44ed002196c5b3fd327662dc123f9899f8ac 100644 (file)
@@ -6,7 +6,7 @@
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains hfs_read_super(), some of the super_ops and
- * init_module() and cleanup_module(). The remaining super_ops are in
+ * init_hfs_fs() and exit_hfs_fs().  The remaining super_ops are in
  * inode.c since they deal with inodes.
  *
  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
index 050d29c0a5b58fae09cfa94c5ae1316f17de8a6a..bb5433608a42efdf3c6ec0ef9b809c614a11b686 100644 (file)
@@ -22,6 +22,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
        struct hfs_btree *tree;
        struct hfs_btree_header_rec *head;
        struct address_space *mapping;
+       struct inode *inode;
        struct page *page;
        unsigned int size;
 
@@ -33,9 +34,10 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
        spin_lock_init(&tree->hash_lock);
        tree->sb = sb;
        tree->cnid = id;
-       tree->inode = iget(sb, id);
-       if (!tree->inode)
+       inode = hfsplus_iget(sb, id);
+       if (IS_ERR(inode))
                goto free_tree;
+       tree->inode = inode;
 
        mapping = tree->inode->i_mapping;
        page = read_mapping_page(mapping, 0, NULL);
index 1955ee61251c670780ecae64b716c95f5653fa59..29683645fa0a7ad7c3d6beb4fbb6be2eddce861c 100644 (file)
@@ -97,9 +97,9 @@ again:
                goto fail;
        }
        hfs_find_exit(&fd);
-       inode = iget(dir->i_sb, cnid);
-       if (!inode)
-               return ERR_PTR(-EACCES);
+       inode = hfsplus_iget(dir->i_sb, cnid);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
        if (S_ISREG(inode->i_mode))
                HFSPLUS_I(inode).dev = linkid;
 out:
index d9f5eda6d039096170beec302d94b5ed6b30dc2f..d72d0a8b25aacf39fd819da29c0963a441f9718a 100644 (file)
@@ -345,6 +345,9 @@ int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
 void hfsplus_fill_defaults(struct hfsplus_sb_info *);
 int hfsplus_show_options(struct seq_file *, struct vfsmount *);
 
+/* super.c */
+struct inode *hfsplus_iget(struct super_block *, unsigned long);
+
 /* tables.c */
 extern u16 hfsplus_case_fold_table[];
 extern u16 hfsplus_decompose_table[];
index ecf70dafb643718e7a91c1c8238290aa16c2fc5a..b0f9ad362d1d45127a2391eb034e1c7e642448df 100644 (file)
@@ -20,11 +20,18 @@ static void hfsplus_destroy_inode(struct inode *inode);
 
 #include "hfsplus_fs.h"
 
-static void hfsplus_read_inode(struct inode *inode)
+struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
 {
        struct hfs_find_data fd;
        struct hfsplus_vh *vhdr;
-       int err;
+       struct inode *inode;
+       long err = -EIO;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
 
        INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
        init_MUTEX(&HFSPLUS_I(inode).extents_lock);
@@ -41,7 +48,7 @@ static void hfsplus_read_inode(struct inode *inode)
                hfs_find_exit(&fd);
                if (err)
                        goto bad_inode;
-               return;
+               goto done;
        }
        vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
        switch(inode->i_ino) {
@@ -70,10 +77,13 @@ static void hfsplus_read_inode(struct inode *inode)
                goto bad_inode;
        }
 
-       return;
+done:
+       unlock_new_inode(inode);
+       return inode;
 
- bad_inode:
-       make_bad_inode(inode);
+bad_inode:
+       iget_failed(inode);
+       return ERR_PTR(err);
 }
 
 static int hfsplus_write_inode(struct inode *inode, int unused)
@@ -262,7 +272,6 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
 static const struct super_operations hfsplus_sops = {
        .alloc_inode    = hfsplus_alloc_inode,
        .destroy_inode  = hfsplus_destroy_inode,
-       .read_inode     = hfsplus_read_inode,
        .write_inode    = hfsplus_write_inode,
        .clear_inode    = hfsplus_clear_inode,
        .put_super      = hfsplus_put_super,
@@ -278,7 +287,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        struct hfsplus_sb_info *sbi;
        hfsplus_cat_entry entry;
        struct hfs_find_data fd;
-       struct inode *root;
+       struct inode *root, *inode;
        struct qstr str;
        struct nls_table *nls = NULL;
        int err = -EINVAL;
@@ -366,18 +375,25 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                goto cleanup;
        }
 
-       HFSPLUS_SB(sb).alloc_file = iget(sb, HFSPLUS_ALLOC_CNID);
-       if (!HFSPLUS_SB(sb).alloc_file) {
+       inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
+       if (IS_ERR(inode)) {
                printk(KERN_ERR "hfs: failed to load allocation file\n");
+               err = PTR_ERR(inode);
                goto cleanup;
        }
+       HFSPLUS_SB(sb).alloc_file = inode;
 
        /* Load the root directory */
-       root = iget(sb, HFSPLUS_ROOT_CNID);
+       root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
+       if (IS_ERR(root)) {
+               printk(KERN_ERR "hfs: failed to load root directory\n");
+               err = PTR_ERR(root);
+               goto cleanup;
+       }
        sb->s_root = d_alloc_root(root);
        if (!sb->s_root) {
-               printk(KERN_ERR "hfs: failed to load root directory\n");
                iput(root);
+               err = -ENOMEM;
                goto cleanup;
        }
        sb->s_root->d_op = &hfsplus_dentry_operations;
@@ -390,9 +406,12 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                hfs_find_exit(&fd);
                if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
                        goto cleanup;
-               HFSPLUS_SB(sb).hidden_dir = iget(sb, be32_to_cpu(entry.folder.id));
-               if (!HFSPLUS_SB(sb).hidden_dir)
+               inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
+               if (IS_ERR(inode)) {
+                       err = PTR_ERR(inode);
                        goto cleanup;
+               }
+               HFSPLUS_SB(sb).hidden_dir = inode;
        } else
                hfs_find_exit(&fd);
 
index 8966b050196e33b2f717fd687dd45df9d58c48bd..2b9b35733aacd00be2673995887521263ae66a39 100644 (file)
@@ -202,7 +202,7 @@ static char *follow_link(char *link)
        return ERR_PTR(n);
 }
 
-static int read_inode(struct inode *ino)
+static int hostfs_read_inode(struct inode *ino)
 {
        char *name;
        int err = 0;
@@ -233,6 +233,25 @@ static int read_inode(struct inode *ino)
        return err;
 }
 
+static struct inode *hostfs_iget(struct super_block *sb)
+{
+       struct inode *inode;
+       long ret;
+
+       inode = iget_locked(sb, 0);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (inode->i_state & I_NEW) {
+               ret = hostfs_read_inode(inode);
+               if (ret < 0) {
+                       iget_failed(inode);
+                       return ERR_PTR(ret);
+               }
+               unlock_new_inode(inode);
+       }
+       return inode;
+}
+
 int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
 {
        /*
@@ -303,17 +322,11 @@ static void hostfs_destroy_inode(struct inode *inode)
        kfree(HOSTFS_I(inode));
 }
 
-static void hostfs_read_inode(struct inode *inode)
-{
-       read_inode(inode);
-}
-
 static const struct super_operations hostfs_sbops = {
        .alloc_inode    = hostfs_alloc_inode,
        .drop_inode     = generic_delete_inode,
        .delete_inode   = hostfs_delete_inode,
        .destroy_inode  = hostfs_destroy_inode,
-       .read_inode     = hostfs_read_inode,
        .statfs         = hostfs_statfs,
 };
 
@@ -571,10 +584,11 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
        char *name;
        int error, fd;
 
-       error = -ENOMEM;
-       inode = iget(dir->i_sb, 0);
-       if (inode == NULL)
+       inode = hostfs_iget(dir->i_sb);
+       if (IS_ERR(inode)) {
+               error = PTR_ERR(inode);
                goto out;
+       }
 
        error = init_inode(inode, dentry);
        if (error)
@@ -615,10 +629,11 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
        char *name;
        int err;
 
-       err = -ENOMEM;
-       inode = iget(ino->i_sb, 0);
-       if (inode == NULL)
+       inode = hostfs_iget(ino->i_sb);
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
                goto out;
+       }
 
        err = init_inode(inode, dentry);
        if (err)
@@ -736,11 +751,13 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 {
        struct inode *inode;
        char *name;
-       int err = -ENOMEM;
+       int err;
 
-       inode = iget(dir->i_sb, 0);
-       if (inode == NULL)
+       inode = hostfs_iget(dir->i_sb);
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
                goto out;
+       }
 
        err = init_inode(inode, dentry);
        if (err)
@@ -952,9 +969,11 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
 
        sprintf(host_root_path, "%s/%s", root_ino, req_root);
 
-       root_inode = iget(sb, 0);
-       if (root_inode == NULL)
+       root_inode = hostfs_iget(sb);
+       if (IS_ERR(root_inode)) {
+               err = PTR_ERR(root_inode);
                goto out_free;
+       }
 
        err = init_inode(root_inode, NULL);
        if (err)
@@ -972,7 +991,7 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
        if (sb->s_root == NULL)
                goto out_put;
 
-       err = read_inode(root_inode);
+       err = hostfs_read_inode(root_inode);
        if (err) {
                /* No iput in this case because the dput does that for us */
                dput(sb->s_root);
index affb7412125e3598b165a5cb3aad71e90227dec7..a1e1f0f61aa5b750971cc81f7369541ed95c0ad0 100644 (file)
@@ -155,6 +155,20 @@ static void hppfs_read_inode(struct inode *ino)
        ino->i_blocks = proc_ino->i_blocks;
 }
 
+static struct inode *hppfs_iget(struct super_block *sb)
+{
+       struct inode *inode;
+
+       inode = iget_locked(sb, 0);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (inode->i_state & I_NEW) {
+               hppfs_read_inode(inode);
+               unlock_new_inode(inode);
+       }
+       return inode;
+}
+
 static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
                                   struct nameidata *nd)
 {
@@ -190,9 +204,11 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
        if(IS_ERR(proc_dentry))
                return(proc_dentry);
 
-       inode = iget(ino->i_sb, 0);
-       if(inode == NULL)
+       inode = hppfs_iget(ino->i_sb);
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
                goto out_dput;
+       }
 
        err = init_inode(inode, proc_dentry);
        if(err)
@@ -652,7 +668,6 @@ static void hppfs_destroy_inode(struct inode *inode)
 static const struct super_operations hppfs_sbops = {
        .alloc_inode    = hppfs_alloc_inode,
        .destroy_inode  = hppfs_destroy_inode,
-       .read_inode     = hppfs_read_inode,
        .delete_inode   = hppfs_delete_inode,
        .statfs         = hppfs_statfs,
 };
@@ -745,9 +760,11 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
        sb->s_magic = HPPFS_SUPER_MAGIC;
        sb->s_op = &hppfs_sbops;
 
-       root_inode = iget(sb, 0);
-       if(root_inode == NULL)
+       root_inode = hppfs_iget(sb);
+       if (IS_ERR(root_inode)) {
+               err = PTR_ERR(root_inode);
                goto out;
+       }
 
        err = init_inode(root_inode, proc_sb->s_root);
        if(err)
index 276ffd6b6fdd61cee59073bf6df95624fead672a..53245ffcf93dc8a4dd4d852257e5cc2e52ed64d6 100644 (file)
@@ -928,8 +928,6 @@ EXPORT_SYMBOL(ilookup);
  * @set:       callback used to initialize a new struct inode
  * @data:      opaque data pointer to pass to @test and @set
  *
- * This is iget() without the read_inode() portion of get_new_inode().
- *
  * iget5_locked() uses ifind() to search for the inode specified by @hashval
  * and @data in the inode cache and if present it is returned with an increased
  * reference count. This is a generalized version of iget_locked() for file
@@ -966,8 +964,6 @@ EXPORT_SYMBOL(iget5_locked);
  * @sb:                super block of file system
  * @ino:       inode number to get
  *
- * This is iget() without the read_inode() portion of get_new_inode_fast().
- *
  * iget_locked() uses ifind_fast() to search for the inode specified by @ino in
  * the inode cache and if present it is returned with an increased reference
  * count. This is for file systems where the inode number is sufficient for
index 2c5b921528760b9da6d8abcc3f90668a8e9381d7..690e72595e6e6048addba645cf179cb418208f50 100644 (file)
@@ -168,20 +168,14 @@ static void set_dentry_child_flags(struct inode *inode, int watched)
                struct dentry *child;
 
                list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
-                       if (!child->d_inode) {
-                               WARN_ON(child->d_flags & DCACHE_INOTIFY_PARENT_WATCHED);
+                       if (!child->d_inode)
                                continue;
-                       }
+
                        spin_lock(&child->d_lock);
-                       if (watched) {
-                               WARN_ON(child->d_flags &
-                                               DCACHE_INOTIFY_PARENT_WATCHED);
+                       if (watched)
                                child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED;
-                       } else {
-                               WARN_ON(!(child->d_flags &
-                                       DCACHE_INOTIFY_PARENT_WATCHED));
-                               child->d_flags&=~DCACHE_INOTIFY_PARENT_WATCHED;
-                       }
+                       else
+                               child->d_flags &=~DCACHE_INOTIFY_PARENT_WATCHED;
                        spin_unlock(&child->d_lock);
                }
        }
@@ -253,7 +247,6 @@ void inotify_d_instantiate(struct dentry *entry, struct inode *inode)
        if (!inode)
                return;
 
-       WARN_ON(entry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED);
        spin_lock(&entry->d_lock);
        parent = entry->d_parent;
        if (parent->d_inode && inotify_inode_watched(parent->d_inode))
@@ -627,6 +620,7 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch,
                      struct inode *inode, u32 mask)
 {
        int ret = 0;
+       int newly_watched;
 
        /* don't allow invalid bits: we don't want flags set */
        mask &= IN_ALL_EVENTS | IN_ONESHOT;
@@ -653,12 +647,18 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch,
         */
        watch->inode = igrab(inode);
 
-       if (!inotify_inode_watched(inode))
-               set_dentry_child_flags(inode, 1);
-
        /* Add the watch to the handle's and the inode's list */
+       newly_watched = !inotify_inode_watched(inode);
        list_add(&watch->h_list, &ih->watches);
        list_add(&watch->i_list, &inode->inotify_watches);
+       /*
+        * Set child flags _after_ adding the watch, so there is no race
+        * windows where newly instantiated children could miss their parent's
+        * watched flag.
+        */
+       if (newly_watched)
+               set_dentry_child_flags(inode, 1);
+
 out:
        mutex_unlock(&ih->mutex);
        mutex_unlock(&inode->inotify_mutex);
index 5e009331c01ff5fbe1a453f735e906e54645368f..a336c9709f3cc477ed15236642b743f0a3ca493e 100644 (file)
@@ -79,6 +79,7 @@ struct inotify_device {
        atomic_t                count;          /* reference count */
        struct user_struct      *user;          /* user who opened this dev */
        struct inotify_handle   *ih;            /* inotify handle */
+       struct fasync_struct    *fa;            /* async notification */
        unsigned int            queue_size;     /* size of the queue (bytes) */
        unsigned int            event_count;    /* number of pending events */
        unsigned int            max_events;     /* maximum number of events */
@@ -247,6 +248,19 @@ inotify_dev_get_event(struct inotify_device *dev)
        return list_entry(dev->events.next, struct inotify_kernel_event, list);
 }
 
+/*
+ * inotify_dev_get_last_event - return the last event in the given dev's queue
+ *
+ * Caller must hold dev->ev_mutex.
+ */
+static inline struct inotify_kernel_event *
+inotify_dev_get_last_event(struct inotify_device *dev)
+{
+       if (list_empty(&dev->events))
+               return NULL;
+       return list_entry(dev->events.prev, struct inotify_kernel_event, list);
+}
+
 /*
  * inotify_dev_queue_event - event handler registered with core inotify, adds
  * a new event to the given device
@@ -273,7 +287,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask,
                put_inotify_watch(w); /* final put */
 
        /* coalescing: drop this event if it is a dupe of the previous */
-       last = inotify_dev_get_event(dev);
+       last = inotify_dev_get_last_event(dev);
        if (last && last->event.mask == mask && last->event.wd == wd &&
                        last->event.cookie == cookie) {
                const char *lastname = last->name;
@@ -302,6 +316,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask,
        dev->queue_size += sizeof(struct inotify_event) + kevent->event.len;
        list_add_tail(&kevent->list, &dev->events);
        wake_up_interruptible(&dev->wq);
+       kill_fasync(&dev->fa, SIGIO, POLL_IN);
 
 out:
        mutex_unlock(&dev->ev_mutex);
@@ -490,6 +505,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
        return ret;
 }
 
+static int inotify_fasync(int fd, struct file *file, int on)
+{
+       struct inotify_device *dev = file->private_data;
+
+       return fasync_helper(fd, file, on, &dev->fa) >= 0 ? 0 : -EIO;
+}
+
 static int inotify_release(struct inode *ignored, struct file *file)
 {
        struct inotify_device *dev = file->private_data;
@@ -502,6 +524,9 @@ static int inotify_release(struct inode *ignored, struct file *file)
                inotify_dev_event_dequeue(dev);
        mutex_unlock(&dev->ev_mutex);
 
+       if (file->f_flags & FASYNC)
+               inotify_fasync(-1, file, 0);
+
        /* free this device: the put matching the get in inotify_init() */
        put_inotify_dev(dev);
 
@@ -530,6 +555,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
 static const struct file_operations inotify_fops = {
        .poll           = inotify_poll,
        .read           = inotify_read,
+       .fasync         = inotify_fasync,
        .release        = inotify_release,
        .unlocked_ioctl = inotify_ioctl,
        .compat_ioctl   = inotify_ioctl,
@@ -577,6 +603,7 @@ asmlinkage long sys_inotify_init(void)
                goto out_free_dev;
        }
        dev->ih = ih;
+       dev->fa = NULL;
 
        filp->f_op = &inotify_fops;
        filp->f_path.mnt = mntget(inotify_mnt);
index c2a773e8620bdd307db7ce16d074f5b4ada2b5b1..683002fefa556875a84c7a0fd79c5249cba04557 100644 (file)
 #include <linux/fs.h>
 #include <linux/security.h>
 #include <linux/module.h>
+#include <linux/uaccess.h>
 
-#include <asm/uaccess.h>
 #include <asm/ioctls.h>
 
-static long do_ioctl(struct file *filp, unsigned int cmd,
-               unsigned long arg)
+/**
+ * vfs_ioctl - call filesystem specific ioctl methods
+ * @filp: [in]     open file to invoke ioctl method on
+ * @cmd:  [in]     ioctl command to execute
+ * @arg:  [in/out] command-specific argument for ioctl
+ *
+ * Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise
+ * invokes * filesystem specific ->ioctl method.  If neither method exists,
+ * returns -ENOTTY.
+ *
+ * Returns 0 on success, -errno on error.
+ */
+long vfs_ioctl(struct file *filp, unsigned int cmd,
+              unsigned long arg)
 {
        int error = -ENOTTY;
 
@@ -40,123 +52,148 @@ static long do_ioctl(struct file *filp, unsigned int cmd,
        return error;
 }
 
+static int ioctl_fibmap(struct file *filp, int __user *p)
+{
+       struct address_space *mapping = filp->f_mapping;
+       int res, block;
+
+       /* do we support this mess? */
+       if (!mapping->a_ops->bmap)
+               return -EINVAL;
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
+       res = get_user(block, p);
+       if (res)
+               return res;
+       lock_kernel();
+       res = mapping->a_ops->bmap(mapping, block);
+       unlock_kernel();
+       return put_user(res, p);
+}
+
 static int file_ioctl(struct file *filp, unsigned int cmd,
                unsigned long arg)
 {
-       int error;
-       int block;
-       struct inode * inode = filp->f_path.dentry->d_inode;
+       struct inode *inode = filp->f_path.dentry->d_inode;
        int __user *p = (int __user *)arg;
 
        switch (cmd) {
-               case FIBMAP:
-               {
-                       struct address_space *mapping = filp->f_mapping;
-                       int res;
-                       /* do we support this mess? */
-                       if (!mapping->a_ops->bmap)
-                               return -EINVAL;
-                       if (!capable(CAP_SYS_RAWIO))
-                               return -EPERM;
-                       if ((error = get_user(block, p)) != 0)
-                               return error;
+       case FIBMAP:
+               return ioctl_fibmap(filp, p);
+       case FIGETBSZ:
+               return put_user(inode->i_sb->s_blocksize, p);
+       case FIONREAD:
+               return put_user(i_size_read(inode) - filp->f_pos, p);
+       }
 
+       return vfs_ioctl(filp, cmd, arg);
+}
+
+static int ioctl_fionbio(struct file *filp, int __user *argp)
+{
+       unsigned int flag;
+       int on, error;
+
+       error = get_user(on, argp);
+       if (error)
+               return error;
+       flag = O_NONBLOCK;
+#ifdef __sparc__
+       /* SunOS compatibility item. */
+       if (O_NONBLOCK != O_NDELAY)
+               flag |= O_NDELAY;
+#endif
+       if (on)
+               filp->f_flags |= flag;
+       else
+               filp->f_flags &= ~flag;
+       return error;
+}
+
+static int ioctl_fioasync(unsigned int fd, struct file *filp,
+                         int __user *argp)
+{
+       unsigned int flag;
+       int on, error;
+
+       error = get_user(on, argp);
+       if (error)
+               return error;
+       flag = on ? FASYNC : 0;
+
+       /* Did FASYNC state change ? */
+       if ((flag ^ filp->f_flags) & FASYNC) {
+               if (filp->f_op && filp->f_op->fasync) {
                        lock_kernel();
-                       res = mapping->a_ops->bmap(mapping, block);
+                       error = filp->f_op->fasync(fd, filp, on);
                        unlock_kernel();
-                       return put_user(res, p);
-               }
-               case FIGETBSZ:
-                       return put_user(inode->i_sb->s_blocksize, p);
-               case FIONREAD:
-                       return put_user(i_size_read(inode) - filp->f_pos, p);
+               } else
+                       error = -ENOTTY;
        }
+       if (error)
+               return error;
 
-       return do_ioctl(filp, cmd, arg);
+       if (on)
+               filp->f_flags |= FASYNC;
+       else
+               filp->f_flags &= ~FASYNC;
+       return error;
 }
 
 /*
  * When you add any new common ioctls to the switches above and below
  * please update compat_sys_ioctl() too.
  *
- * vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
+ * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
  * It's just a simple helper for sys_ioctl and compat_sys_ioctl.
  */
-int vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, unsigned long arg)
+int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
+            unsigned long arg)
 {
-       unsigned int flag;
-       int on, error = 0;
+       int error = 0;
+       int __user *argp = (int __user *)arg;
 
        switch (cmd) {
-               case FIOCLEX:
-                       set_close_on_exec(fd, 1);
-                       break;
-
-               case FIONCLEX:
-                       set_close_on_exec(fd, 0);
-                       break;
-
-               case FIONBIO:
-                       if ((error = get_user(on, (int __user *)arg)) != 0)
-                               break;
-                       flag = O_NONBLOCK;
-#ifdef __sparc__
-                       /* SunOS compatibility item. */
-                       if(O_NONBLOCK != O_NDELAY)
-                               flag |= O_NDELAY;
-#endif
-                       if (on)
-                               filp->f_flags |= flag;
-                       else
-                               filp->f_flags &= ~flag;
-                       break;
-
-               case FIOASYNC:
-                       if ((error = get_user(on, (int __user *)arg)) != 0)
-                               break;
-                       flag = on ? FASYNC : 0;
-
-                       /* Did FASYNC state change ? */
-                       if ((flag ^ filp->f_flags) & FASYNC) {
-                               if (filp->f_op && filp->f_op->fasync) {
-                                       lock_kernel();
-                                       error = filp->f_op->fasync(fd, filp, on);
-                                       unlock_kernel();
-                               }
-                               else error = -ENOTTY;
-                       }
-                       if (error != 0)
-                               break;
-
-                       if (on)
-                               filp->f_flags |= FASYNC;
-                       else
-                               filp->f_flags &= ~FASYNC;
-                       break;
-
-               case FIOQSIZE:
-                       if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) ||
-                           S_ISREG(filp->f_path.dentry->d_inode->i_mode) ||
-                           S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) {
-                               loff_t res = inode_get_bytes(filp->f_path.dentry->d_inode);
-                               error = copy_to_user((loff_t __user *)arg, &res, sizeof(res)) ? -EFAULT : 0;
-                       }
-                       else
-                               error = -ENOTTY;
-                       break;
-               default:
-                       if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
-                               error = file_ioctl(filp, cmd, arg);
-                       else
-                               error = do_ioctl(filp, cmd, arg);
-                       break;
+       case FIOCLEX:
+               set_close_on_exec(fd, 1);
+               break;
+
+       case FIONCLEX:
+               set_close_on_exec(fd, 0);
+               break;
+
+       case FIONBIO:
+               error = ioctl_fionbio(filp, argp);
+               break;
+
+       case FIOASYNC:
+               error = ioctl_fioasync(fd, filp, argp);
+               break;
+
+       case FIOQSIZE:
+               if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) ||
+                   S_ISREG(filp->f_path.dentry->d_inode->i_mode) ||
+                   S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) {
+                       loff_t res =
+                               inode_get_bytes(filp->f_path.dentry->d_inode);
+                       error = copy_to_user((loff_t __user *)arg, &res,
+                                            sizeof(res)) ? -EFAULT : 0;
+               } else
+                       error = -ENOTTY;
+               break;
+       default:
+               if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
+                       error = file_ioctl(filp, cmd, arg);
+               else
+                       error = vfs_ioctl(filp, cmd, arg);
+               break;
        }
        return error;
 }
 
 asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-       struct file * filp;
+       struct file *filp;
        int error = -EBADF;
        int fput_needed;
 
@@ -168,7 +205,7 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        if (error)
                goto out_fput;
 
-       error = vfs_ioctl(filp, fd, cmd, arg);
+       error = do_vfs_ioctl(filp, fd, cmd, arg);
  out_fput:
        fput_light(filp, fput_needed);
  out:
index 29f9753ae5e5ba45c25eec7eaf26261ab6441b42..bb219138331a23672b53bbbf74ee20a0afe920b3 100644 (file)
@@ -26,11 +26,9 @@ isofs_export_iget(struct super_block *sb,
        if (block == 0)
                return ERR_PTR(-ESTALE);
        inode = isofs_iget(sb, block, offset);
-       if (inode == NULL)
-               return ERR_PTR(-ENOMEM);
-       if (is_bad_inode(inode)
-           || (generation && inode->i_generation != generation))
-       {
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       if (generation && inode->i_generation != generation) {
                iput(inode);
                return ERR_PTR(-ESTALE);
        }
@@ -110,8 +108,10 @@ static struct dentry *isofs_export_get_parent(struct dentry *child)
        parent_inode = isofs_iget(child_inode->i_sb,
                                  parent_block,
                                  parent_offset);
-       if (parent_inode == NULL) {
-               rv = ERR_PTR(-EACCES);
+       if (IS_ERR(parent_inode)) {
+               rv = ERR_CAST(parent_inode);
+               if (rv != ERR_PTR(-ENOMEM))
+                       rv = ERR_PTR(-EACCES);
                goto out;
        }
 
index 09e3d306e96fb298518f50bac38d4ee697b4bf8c..875d37fb6c70f7da561833e5af1a34d048fd4d9a 100644 (file)
@@ -54,7 +54,7 @@ static void isofs_put_super(struct super_block *sb)
        return;
 }
 
-static void isofs_read_inode(struct inode *);
+static int isofs_read_inode(struct inode *);
 static int isofs_statfs (struct dentry *, struct kstatfs *);
 
 static struct kmem_cache *isofs_inode_cachep;
@@ -107,7 +107,6 @@ static int isofs_remount(struct super_block *sb, int *flags, char *data)
 static const struct super_operations isofs_sops = {
        .alloc_inode    = isofs_alloc_inode,
        .destroy_inode  = isofs_destroy_inode,
-       .read_inode     = isofs_read_inode,
        .put_super      = isofs_put_super,
        .statfs         = isofs_statfs,
        .remount_fs     = isofs_remount,
@@ -552,7 +551,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
        int joliet_level = 0;
        int iso_blknum, block;
        int orig_zonesize;
-       int table;
+       int table, error = -EINVAL;
        unsigned int vol_desc_start;
 
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
@@ -810,6 +809,8 @@ root_found:
         * we then decide whether to use the Joliet descriptor.
         */
        inode = isofs_iget(s, sbi->s_firstdatazone, 0);
+       if (IS_ERR(inode))
+               goto out_no_root;
 
        /*
         * If this disk has both Rock Ridge and Joliet on it, then we
@@ -829,6 +830,8 @@ root_found:
                                "ISOFS: changing to secondary root\n");
                        iput(inode);
                        inode = isofs_iget(s, sbi->s_firstdatazone, 0);
+                       if (IS_ERR(inode))
+                               goto out_no_root;
                }
        }
 
@@ -842,8 +845,6 @@ root_found:
        sbi->s_joliet_level = joliet_level;
 
        /* check the root inode */
-       if (!inode)
-               goto out_no_root;
        if (!inode->i_op)
                goto out_bad_root;
 
@@ -876,11 +877,14 @@ root_found:
         */
 out_bad_root:
        printk(KERN_WARNING "%s: root inode not initialized\n", __func__);
-       goto out_iput;
-out_no_root:
-       printk(KERN_WARNING "%s: get root inode failed\n", __func__);
 out_iput:
        iput(inode);
+       goto out_no_inode;
+out_no_root:
+       error = PTR_ERR(inode);
+       if (error != -ENOMEM)
+               printk(KERN_WARNING "%s: get root inode failed\n", __func__);
+out_no_inode:
 #ifdef CONFIG_JOLIET
        if (sbi->s_nls_iocharset)
                unload_nls(sbi->s_nls_iocharset);
@@ -908,7 +912,7 @@ out_freesbi:
        kfree(opt.iocharset);
        kfree(sbi);
        s->s_fs_info = NULL;
-       return -EINVAL;
+       return error;
 }
 
 static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
@@ -930,7 +934,7 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
 /*
  * Get a set of blocks; filling in buffer_heads if already allocated
  * or getblk() if they are not.  Returns the number of blocks inserted
- * (0 == error.)
+ * (-ve == error.)
  */
 int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
                     struct buffer_head **bh, unsigned long nblocks)
@@ -940,11 +944,12 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
        unsigned int firstext;
        unsigned long nextblk, nextoff;
        long iblock = (long)iblock_s;
-       int section, rv;
+       int section, rv, error;
        struct iso_inode_info *ei = ISOFS_I(inode);
 
        lock_kernel();
 
+       error = -EIO;
        rv = 0;
        if (iblock < 0 || iblock != iblock_s) {
                printk(KERN_DEBUG "%s: block number too large\n", __func__);
@@ -983,8 +988,10 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
 
                        offset += sect_size;
                        ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
-                       if (!ninode)
+                       if (IS_ERR(ninode)) {
+                               error = PTR_ERR(ninode);
                                goto abort;
+                       }
                        firstext  = ISOFS_I(ninode)->i_first_extent;
                        sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
                        nextblk   = ISOFS_I(ninode)->i_next_section_block;
@@ -1015,9 +1022,10 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
                rv++;
        }
 
+       error = 0;
 abort:
        unlock_kernel();
-       return rv;
+       return rv != 0 ? rv : error;
 }
 
 /*
@@ -1026,12 +1034,15 @@ abort:
 static int isofs_get_block(struct inode *inode, sector_t iblock,
                    struct buffer_head *bh_result, int create)
 {
+       int ret;
+
        if (create) {
                printk(KERN_DEBUG "%s: Kernel tries to allocate a block\n", __func__);
                return -EROFS;
        }
 
-       return isofs_get_blocks(inode, iblock, &bh_result, 1) ? 0 : -EIO;
+       ret = isofs_get_blocks(inode, iblock, &bh_result, 1);
+       return ret < 0 ? ret : 0;
 }
 
 static int isofs_bmap(struct inode *inode, sector_t block)
@@ -1186,7 +1197,7 @@ out_toomany:
        goto out;
 }
 
-static void isofs_read_inode(struct inode *inode)
+static int isofs_read_inode(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
        struct isofs_sb_info *sbi = ISOFS_SB(sb);
@@ -1199,6 +1210,7 @@ static void isofs_read_inode(struct inode *inode)
        unsigned int de_len;
        unsigned long offset;
        struct iso_inode_info *ei = ISOFS_I(inode);
+       int ret = -EIO;
 
        block = ei->i_iget5_block;
        bh = sb_bread(inode->i_sb, block);
@@ -1216,6 +1228,7 @@ static void isofs_read_inode(struct inode *inode)
                tmpde = kmalloc(de_len, GFP_KERNEL);
                if (tmpde == NULL) {
                        printk(KERN_INFO "%s: out of memory\n", __func__);
+                       ret = -ENOMEM;
                        goto fail;
                }
                memcpy(tmpde, bh->b_data + offset, frag1);
@@ -1259,8 +1272,10 @@ static void isofs_read_inode(struct inode *inode)
 
        ei->i_section_size = isonum_733(de->size);
        if (de->flags[-high_sierra] & 0x80) {
-               if(isofs_read_level3_size(inode))
+               ret = isofs_read_level3_size(inode);
+               if (ret < 0)
                        goto fail;
+               ret = -EIO;
        } else {
                ei->i_next_section_block = 0;
                ei->i_next_section_offset = 0;
@@ -1346,16 +1361,16 @@ static void isofs_read_inode(struct inode *inode)
                /* XXX - parse_rock_ridge_inode() had already set i_rdev. */
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
 
+       ret = 0;
 out:
        kfree(tmpde);
        if (bh)
                brelse(bh);
-       return;
+       return ret;
 
 out_badread:
        printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
 fail:
-       make_bad_inode(inode);
        goto out;
 }
 
@@ -1394,9 +1409,10 @@ struct inode *isofs_iget(struct super_block *sb,
        unsigned long hashval;
        struct inode *inode;
        struct isofs_iget5_callback_data data;
+       long ret;
 
        if (offset >= 1ul << sb->s_blocksize_bits)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        data.block = block;
        data.offset = offset;
@@ -1406,9 +1422,17 @@ struct inode *isofs_iget(struct super_block *sb,
        inode = iget5_locked(sb, hashval, &isofs_iget5_test,
                                &isofs_iget5_set, &data);
 
-       if (inode && (inode->i_state & I_NEW)) {
-               sb->s_op->read_inode(inode);
-               unlock_new_inode(inode);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
+       if (inode->i_state & I_NEW) {
+               ret = isofs_read_inode(inode);
+               if (ret < 0) {
+                       iget_failed(inode);
+                       inode = ERR_PTR(ret);
+               } else {
+                       unlock_new_inode(inode);
+               }
        }
 
        return inode;
index e2b4dad39ca9d34641846284f43e51dc2715a095..344b247bc29ab1f104fcc25af9a831052267baad 100644 (file)
@@ -179,9 +179,9 @@ struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nam
        inode = NULL;
        if (found) {
                inode = isofs_iget(dir->i_sb, block, offset);
-               if (!inode) {
+               if (IS_ERR(inode)) {
                        unlock_kernel();
-                       return ERR_PTR(-EACCES);
+                       return ERR_CAST(inode);
                }
        }
        unlock_kernel();
index f3a1db3098deadef58b46d7cec786d9fe8c6dae9..6bd48f0a7047d7560f06492dfe57e53141be6a17 100644 (file)
@@ -474,8 +474,10 @@ repeat:
                            isofs_iget(inode->i_sb,
                                       ISOFS_I(inode)->i_first_extent,
                                       0);
-                       if (!reloc)
+                       if (IS_ERR(reloc)) {
+                               ret = PTR_ERR(reloc);
                                goto out;
+                       }
                        inode->i_mode = reloc->i_mode;
                        inode->i_nlink = reloc->i_nlink;
                        inode->i_uid = reloc->i_uid;
index 5d14243499d47d117fa662620f34da9d3bd76ed8..3943a8905eb2595e4f43594e778f0e0f7c69f94a 100644 (file)
@@ -1457,7 +1457,7 @@ static const char *journal_dev_name(journal_t *journal, char *buffer)
  * Aborts hard --- we mark the abort as occurred, but do _nothing_ else,
  * and don't attempt to make any other journal updates.
  */
-void __journal_abort_hard(journal_t *journal)
+static void __journal_abort_hard(journal_t *journal)
 {
        transaction_t *transaction;
        char b[BDEVNAME_SIZE];
index c5d9694b6a2ff2df7f9311942674321c05147c88..2b8edf4d6eaa6462c59f055f81017954d92b0e39 100644 (file)
@@ -354,7 +354,7 @@ static int do_one_pass(journal_t *journal,
                struct buffer_head *    obh;
                struct buffer_head *    nbh;
 
-               cond_resched();         /* We're under lock_kernel() */
+               cond_resched();
 
                /* If we already know where to stop the log traversal,
                 * check right now that we haven't gone past the end of
index 921680663fa2771319837ad1ff24d4c8f9d8c55e..d36356f7d222c94f63f5c64d16137a2692c09841 100644 (file)
@@ -397,7 +397,7 @@ static int do_one_pass(journal_t *journal,
                struct buffer_head *    obh;
                struct buffer_head *    nbh;
 
-               cond_resched();         /* We're under lock_kernel() */
+               cond_resched();
 
                /* If we already know where to stop the log traversal,
                 * check right now that we haven't gone past the end of
index 787e392ffd41bac38f0d3db617b0070faed368f6..f948f7e6ec8202ab901d83b7fd5c62fd6ec41b27 100644 (file)
@@ -101,10 +101,10 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
                ino = fd->ino;
        up(&dir_f->sem);
        if (ino) {
-               inode = iget(dir_i->i_sb, ino);
-               if (!inode) {
+               inode = jffs2_iget(dir_i->i_sb, ino);
+               if (IS_ERR(inode)) {
                        printk(KERN_WARNING "iget() failed for ino #%u\n", ino);
-                       return (ERR_PTR(-EIO));
+                       return ERR_CAST(inode);
                }
        }
 
index d2e06f7ea96fdff2eac4a3c683c026e5c5d9fac6..6d1eaddde0ecd70426eb5f760f9e6f1460ad7826 100644 (file)
@@ -230,16 +230,23 @@ void jffs2_clear_inode (struct inode *inode)
        jffs2_do_clear_inode(c, f);
 }
 
-void jffs2_read_inode (struct inode *inode)
+struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
 {
        struct jffs2_inode_info *f;
        struct jffs2_sb_info *c;
        struct jffs2_raw_inode latest_node;
        union jffs2_device_node jdev;
+       struct inode *inode;
        dev_t rdev = 0;
        int ret;
 
-       D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
+       D1(printk(KERN_DEBUG "jffs2_iget(): ino == %lu\n", ino));
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
 
        f = JFFS2_INODE_INFO(inode);
        c = JFFS2_SB_INFO(inode->i_sb);
@@ -250,9 +257,9 @@ void jffs2_read_inode (struct inode *inode)
        ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
 
        if (ret) {
-               make_bad_inode(inode);
                up(&f->sem);
-               return;
+               iget_failed(inode);
+               return ERR_PTR(ret);
        }
        inode->i_mode = jemode_to_cpu(latest_node.mode);
        inode->i_uid = je16_to_cpu(latest_node.uid);
@@ -303,19 +310,14 @@ void jffs2_read_inode (struct inode *inode)
                if (f->metadata->size != sizeof(jdev.old) &&
                    f->metadata->size != sizeof(jdev.new)) {
                        printk(KERN_NOTICE "Device node has strange size %d\n", f->metadata->size);
-                       up(&f->sem);
-                       jffs2_do_clear_inode(c, f);
-                       make_bad_inode(inode);
-                       return;
+                       goto error_io;
                }
                D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
-               if (jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size) < 0) {
+               ret = jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size);
+               if (ret < 0) {
                        /* Eep */
                        printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
-                       up(&f->sem);
-                       jffs2_do_clear_inode(c, f);
-                       make_bad_inode(inode);
-                       return;
+                       goto error;
                }
                if (f->metadata->size == sizeof(jdev.old))
                        rdev = old_decode_dev(je16_to_cpu(jdev.old));
@@ -335,6 +337,16 @@ void jffs2_read_inode (struct inode *inode)
        up(&f->sem);
 
        D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
+       unlock_new_inode(inode);
+       return inode;
+
+error_io:
+       ret = -EIO;
+error:
+       up(&f->sem);
+       jffs2_do_clear_inode(c, f);
+       iget_failed(inode);
+       return ERR_PTR(ret);
 }
 
 void jffs2_dirty_inode(struct inode *inode)
@@ -522,15 +534,16 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
        if ((ret = jffs2_do_mount_fs(c)))
                goto out_inohash;
 
-       ret = -EINVAL;
-
        D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode\n"));
-       root_i = iget(sb, 1);
-       if (is_bad_inode(root_i)) {
+       root_i = jffs2_iget(sb, 1);
+       if (IS_ERR(root_i)) {
                D1(printk(KERN_WARNING "get root inode failed\n"));
-               goto out_root_i;
+               ret = PTR_ERR(root_i);
+               goto out_root;
        }
 
+       ret = -ENOMEM;
+
        D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n"));
        sb->s_root = d_alloc_root(root_i);
        if (!sb->s_root)
@@ -546,6 +559,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
 
  out_root_i:
        iput(root_i);
+out_root:
        jffs2_free_ino_caches(c);
        jffs2_free_raw_node_refs(c);
        if (jffs2_blocks_use_vmalloc(c))
@@ -615,9 +629,9 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
                   jffs2_do_unlink() would need the alloc_sem and we have it.
                   Just iget() it, and if read_inode() is necessary that's OK.
                */
-               inode = iget(OFNI_BS_2SFFJ(c), inum);
-               if (!inode)
-                       return ERR_PTR(-ENOMEM);
+               inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum);
+               if (IS_ERR(inode))
+                       return ERR_CAST(inode);
        }
        if (is_bad_inode(inode)) {
                printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
index bf64686cf09848b5d9a0730114ed17fe367c8e5e..1b10d2594092b87cf8505e9237e93f02abf09737 100644 (file)
@@ -175,7 +175,7 @@ extern const struct inode_operations jffs2_symlink_inode_operations;
 /* fs.c */
 int jffs2_setattr (struct dentry *, struct iattr *);
 int jffs2_do_setattr (struct inode *, struct iattr *);
-void jffs2_read_inode (struct inode *);
+struct inode *jffs2_iget(struct super_block *, unsigned long);
 void jffs2_clear_inode (struct inode *);
 void jffs2_dirty_inode(struct inode *inode);
 struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
index ffa447511e6a38d5cb6f194eb8c64a51878b91fd..4677355996cc8c49a284e56a909502fe788cf234 100644 (file)
@@ -65,7 +65,6 @@ static const struct super_operations jffs2_super_operations =
 {
        .alloc_inode =  jffs2_alloc_inode,
        .destroy_inode =jffs2_destroy_inode,
-       .read_inode =   jffs2_read_inode,
        .put_super =    jffs2_put_super,
        .write_super =  jffs2_write_super,
        .statfs =       jffs2_statfs,
index 147e2cbee9e465168f37f0837c2ea04854eadb1f..1b88e6e734efa17e9c0c4e517b984bf3759640c4 100644 (file)
@@ -177,7 +177,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
                void *hold_err = fn->raw;
                /* Release the full_dnode which is now useless, and return */
                jffs2_free_full_dnode(fn);
-               return ERR_PTR(PTR_ERR(hold_err));
+               return ERR_CAST(hold_err);
        }
        fn->ofs = je32_to_cpu(ri->offset);
        fn->size = je32_to_cpu(ri->dsize);
@@ -313,7 +313,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
                void *hold_err = fd->raw;
                /* Release the full_dirent which is now useless, and return */
                jffs2_free_full_dirent(fd);
-               return ERR_PTR(PTR_ERR(hold_err));
+               return ERR_CAST(hold_err);
        }
 
        if (retried) {
index 4672013802e126a9f0d0da9f14947ebfa6830cb9..210339784b56f98a29ca2d75e2c2cf082dae904a 100644 (file)
 #include "jfs_debug.h"
 
 
-void jfs_read_inode(struct inode *inode)
+struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
 {
-       if (diRead(inode)) {
-               make_bad_inode(inode);
-               return;
+       struct inode *inode;
+       int ret;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       ret = diRead(inode);
+       if (ret < 0) {
+               iget_failed(inode);
+               return ERR_PTR(ret);
        }
 
        if (S_ISREG(inode->i_mode)) {
@@ -55,6 +65,8 @@ void jfs_read_inode(struct inode *inode)
                inode->i_op = &jfs_file_inode_operations;
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
        }
+       unlock_new_inode(inode);
+       return inode;
 }
 
 /*
index 8e2cf2cde185d67571489bacf321f45feeef5131..95a6a11425e595e75d503ac1d4a5a1fb0fdde6a8 100644 (file)
@@ -24,7 +24,7 @@ extern struct inode *ialloc(struct inode *, umode_t);
 extern int jfs_fsync(struct file *, struct dentry *, int);
 extern int jfs_ioctl(struct inode *, struct file *,
                        unsigned int, unsigned long);
-extern void jfs_read_inode(struct inode *);
+extern struct inode *jfs_iget(struct super_block *, unsigned long);
 extern int jfs_commit_inode(struct inode *, int);
 extern int jfs_write_inode(struct inode*, int);
 extern void jfs_delete_inode(struct inode *);
index f8718de3505e9fc56805b5a338fbb244c59e3488..403cfc24c6fe23155848e771c97ef344e3fc17a5 100644 (file)
@@ -1462,12 +1462,10 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
                }
        }
 
-       ip = iget(dip->i_sb, inum);
-       if (ip == NULL || is_bad_inode(ip)) {
+       ip = jfs_iget(dip->i_sb, inum);
+       if (IS_ERR(ip)) {
                jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum);
-               if (ip)
-                       iput(ip);
-               return ERR_PTR(-EACCES);
+               return ERR_CAST(ip);
        }
 
        dentry = d_splice_alias(ip, dentry);
@@ -1485,12 +1483,11 @@ static struct inode *jfs_nfs_get_inode(struct super_block *sb,
 
        if (ino == 0)
                return ERR_PTR(-ESTALE);
-       inode = iget(sb, ino);
-       if (inode == NULL)
-               return ERR_PTR(-ENOMEM);
+       inode = jfs_iget(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
 
-       if (is_bad_inode(inode) ||
-           (generation && inode->i_generation != generation)) {
+       if (generation && inode->i_generation != generation) {
                iput(inode);
                return ERR_PTR(-ESTALE);
        }
@@ -1521,17 +1518,14 @@ struct dentry *jfs_get_parent(struct dentry *dentry)
 
        parent_ino =
                le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot);
-       inode = iget(sb, parent_ino);
-       if (inode) {
-               if (is_bad_inode(inode)) {
+       inode = jfs_iget(sb, parent_ino);
+       if (IS_ERR(inode)) {
+               parent = ERR_CAST(inode);
+       } else {
+               parent = d_alloc_anon(inode);
+               if (!parent) {
+                       parent = ERR_PTR(-ENOMEM);
                        iput(inode);
-                       parent = ERR_PTR(-EACCES);
-               } else {
-                       parent = d_alloc_anon(inode);
-                       if (!parent) {
-                               parent = ERR_PTR(-ENOMEM);
-                               iput(inode);
-                       }
                }
        }
 
index 70a14001c98f4c3b13a523346635195fb51cae96..50ea65451732edf196c7750c2e1f0ee60b547bba 100644 (file)
@@ -414,7 +414,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *inode;
        int rc;
        s64 newLVSize = 0;
-       int flag;
+       int flag, ret = -EINVAL;
 
        jfs_info("In jfs_read_super: s_flags=0x%lx", sb->s_flags);
 
@@ -461,8 +461,10 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
         * Initialize direct-mapping inode/address-space
         */
        inode = new_inode(sb);
-       if (inode == NULL)
+       if (inode == NULL) {
+               ret = -ENOMEM;
                goto out_kfree;
+       }
        inode->i_ino = 0;
        inode->i_nlink = 1;
        inode->i_size = sb->s_bdev->bd_inode->i_size;
@@ -494,9 +496,11 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_magic = JFS_SUPER_MAGIC;
 
-       inode = iget(sb, ROOT_I);
-       if (!inode || is_bad_inode(inode))
+       inode = jfs_iget(sb, ROOT_I);
+       if (IS_ERR(inode)) {
+               ret = PTR_ERR(inode);
                goto out_no_root;
+       }
        sb->s_root = d_alloc_root(inode);
        if (!sb->s_root)
                goto out_no_root;
@@ -536,7 +540,7 @@ out_kfree:
        if (sbi->nls_tab)
                unload_nls(sbi->nls_tab);
        kfree(sbi);
-       return -EINVAL;
+       return ret;
 }
 
 static void jfs_write_super_lockfs(struct super_block *sb)
@@ -726,7 +730,6 @@ out:
 static const struct super_operations jfs_super_operations = {
        .alloc_inode    = jfs_alloc_inode,
        .destroy_inode  = jfs_destroy_inode,
-       .read_inode     = jfs_read_inode,
        .dirty_inode    = jfs_dirty_inode,
        .write_inode    = jfs_write_inode,
        .delete_inode   = jfs_delete_inode,
index bf4cd316af81cb91b602d2a06895756461becc5e..84f6242ba6fc7262b2cf90a7d126f5192c6a13d9 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/highuid.h>
 #include <linux/vfs.h>
 
-static void minix_read_inode(struct inode * inode);
 static int minix_write_inode(struct inode * inode, int wait);
 static int minix_statfs(struct dentry *dentry, struct kstatfs *buf);
 static int minix_remount (struct super_block * sb, int * flags, char * data);
@@ -96,7 +95,6 @@ static void destroy_inodecache(void)
 static const struct super_operations minix_sops = {
        .alloc_inode    = minix_alloc_inode,
        .destroy_inode  = minix_destroy_inode,
-       .read_inode     = minix_read_inode,
        .write_inode    = minix_write_inode,
        .delete_inode   = minix_delete_inode,
        .put_super      = minix_put_super,
@@ -149,6 +147,7 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
        unsigned long i, block;
        struct inode *root_inode;
        struct minix_sb_info *sbi;
+       int ret = -EINVAL;
 
        sbi = kzalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
        if (!sbi)
@@ -246,10 +245,13 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
 
        /* set up enough so that it can read an inode */
        s->s_op = &minix_sops;
-       root_inode = iget(s, MINIX_ROOT_INO);
-       if (!root_inode || is_bad_inode(root_inode))
+       root_inode = minix_iget(s, MINIX_ROOT_INO);
+       if (IS_ERR(root_inode)) {
+               ret = PTR_ERR(root_inode);
                goto out_no_root;
+       }
 
+       ret = -ENOMEM;
        s->s_root = d_alloc_root(root_inode);
        if (!s->s_root)
                goto out_iput;
@@ -290,6 +292,7 @@ out_freemap:
        goto out_release;
 
 out_no_map:
+       ret = -ENOMEM;
        if (!silent)
                printk("MINIX-fs: can't allocate map\n");
        goto out_release;
@@ -316,7 +319,7 @@ out_bad_sb:
 out:
        s->s_fs_info = NULL;
        kfree(sbi);
-       return -EINVAL;
+       return ret;
 }
 
 static int minix_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -409,7 +412,7 @@ void minix_set_inode(struct inode *inode, dev_t rdev)
 /*
  * The minix V1 function to read an inode.
  */
-static void V1_minix_read_inode(struct inode * inode)
+static struct inode *V1_minix_iget(struct inode *inode)
 {
        struct buffer_head * bh;
        struct minix_inode * raw_inode;
@@ -418,8 +421,8 @@ static void V1_minix_read_inode(struct inode * inode)
 
        raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
        if (!raw_inode) {
-               make_bad_inode(inode);
-               return;
+               iget_failed(inode);
+               return ERR_PTR(-EIO);
        }
        inode->i_mode = raw_inode->i_mode;
        inode->i_uid = (uid_t)raw_inode->i_uid;
@@ -435,12 +438,14 @@ static void V1_minix_read_inode(struct inode * inode)
                minix_inode->u.i1_data[i] = raw_inode->i_zone[i];
        minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
        brelse(bh);
+       unlock_new_inode(inode);
+       return inode;
 }
 
 /*
  * The minix V2 function to read an inode.
  */
-static void V2_minix_read_inode(struct inode * inode)
+static struct inode *V2_minix_iget(struct inode *inode)
 {
        struct buffer_head * bh;
        struct minix2_inode * raw_inode;
@@ -449,8 +454,8 @@ static void V2_minix_read_inode(struct inode * inode)
 
        raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
        if (!raw_inode) {
-               make_bad_inode(inode);
-               return;
+               iget_failed(inode);
+               return ERR_PTR(-EIO);
        }
        inode->i_mode = raw_inode->i_mode;
        inode->i_uid = (uid_t)raw_inode->i_uid;
@@ -468,17 +473,27 @@ static void V2_minix_read_inode(struct inode * inode)
                minix_inode->u.i2_data[i] = raw_inode->i_zone[i];
        minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
        brelse(bh);
+       unlock_new_inode(inode);
+       return inode;
 }
 
 /*
  * The global function to read an inode.
  */
-static void minix_read_inode(struct inode * inode)
+struct inode *minix_iget(struct super_block *sb, unsigned long ino)
 {
+       struct inode *inode;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
        if (INODE_VERSION(inode) == MINIX_V1)
-               V1_minix_read_inode(inode);
+               return V1_minix_iget(inode);
        else
-               V2_minix_read_inode(inode);
+               return V2_minix_iget(inode);
 }
 
 /*
index ac5d3a75cb0d1358fa00a744756ef1ceb4f39df8..326edfe96108f5eec496d57bd96092ff25b5e366 100644 (file)
@@ -45,6 +45,7 @@ struct minix_sb_info {
        unsigned short s_version;
 };
 
+extern struct inode *minix_iget(struct super_block *, unsigned long);
 extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
 extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
 extern struct inode * minix_new_inode(const struct inode * dir, int * error);
index f4aa7a9390406b9f27cbd2fc9aaa4ddbc48dcf8d..102241bc9c7965e646585d871f4e1436a0057ccb 100644 (file)
@@ -54,10 +54,9 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, st
 
        ino = minix_inode_by_name(dentry);
        if (ino) {
-               inode = iget(dir->i_sb, ino);
-               if (!inode)
-                       return ERR_PTR(-EACCES);
+               inode = minix_iget(dir->i_sb, ino);
+               if (IS_ERR(inode))
+                       return ERR_CAST(inode);
        }
        d_add(dentry, inode);
        return NULL;
index 73e2e665817a100c9f05c33a12756f639d9c5ae7..241cff423653692ec067afa71ccf9c8ca4e86b05 100644 (file)
@@ -2188,6 +2188,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
 
        /* We don't d_delete() NFS sillyrenamed files--they still exist. */
        if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
+               fsnotify_link_count(dentry->d_inode);
                d_delete(dentry);
        }
 
@@ -2360,7 +2361,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        error = dir->i_op->link(old_dentry, dir, new_dentry);
        mutex_unlock(&old_dentry->d_inode->i_mutex);
        if (!error)
-               fsnotify_create(dir, new_dentry);
+               fsnotify_link(dir, old_dentry->d_inode, new_dentry);
        return error;
 }
 
index 61bf376e29e85bfda2456cb929c0a0eeb38af1b3..e9c10cd01e1325cff95869cbb0f23aa8d14c10ce 100644 (file)
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/ramfs.h>
+#include <linux/log2.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include "pnode.h"
 #include "internal.h"
 
+#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head))
+#define HASH_SIZE (1UL << HASH_SHIFT)
+
 /* spinlock for vfsmount related operations, inplace of dcache_lock */
 __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
 
 static int event;
 
 static struct list_head *mount_hashtable __read_mostly;
-static int hash_mask __read_mostly, hash_bits __read_mostly;
 static struct kmem_cache *mnt_cache __read_mostly;
 static struct rw_semaphore namespace_sem;
 
@@ -48,8 +51,8 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
        unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
        tmp += ((unsigned long)dentry / L1_CACHE_BYTES);
-       tmp = tmp + (tmp >> hash_bits);
-       return tmp & hash_mask;
+       tmp = tmp + (tmp >> HASH_SHIFT);
+       return tmp & (HASH_SIZE - 1);
 }
 
 struct vfsmount *alloc_vfsmnt(const char *name)
@@ -1813,9 +1816,7 @@ static void __init init_mount_tree(void)
 
 void __init mnt_init(void)
 {
-       struct list_head *d;
-       unsigned int nr_hash;
-       int i;
+       unsigned u;
        int err;
 
        init_rwsem(&namespace_sem);
@@ -1828,35 +1829,11 @@ void __init mnt_init(void)
        if (!mount_hashtable)
                panic("Failed to allocate mount hash table\n");
 
-       /*
-        * Find the power-of-two list-heads that can fit into the allocation..
-        * We don't guarantee that "sizeof(struct list_head)" is necessarily
-        * a power-of-two.
-        */
-       nr_hash = PAGE_SIZE / sizeof(struct list_head);
-       hash_bits = 0;
-       do {
-               hash_bits++;
-       } while ((nr_hash >> hash_bits) != 0);
-       hash_bits--;
+       printk("Mount-cache hash table entries: %lu\n", HASH_SIZE);
+
+       for (u = 0; u < HASH_SIZE; u++)
+               INIT_LIST_HEAD(&mount_hashtable[u]);
 
-       /*
-        * Re-calculate the actual number of entries and the mask
-        * from the number of bits we can fit.
-        */
-       nr_hash = 1UL << hash_bits;
-       hash_mask = nr_hash - 1;
-
-       printk("Mount-cache hash table entries: %d\n", nr_hash);
-
-       /* And initialize the newly allocated array */
-       d = mount_hashtable;
-       i = nr_hash;
-       do {
-               INIT_LIST_HEAD(d);
-               d++;
-               i--;
-       } while (i);
        err = sysfs_init();
        if (err)
                printk(KERN_WARNING "%s: sysfs_init error: %d\n",
index e1cb70c643f8f81f599ad1da0c76cc9080aba332..eff1f18d034f1b2510aa6ef54c71427bda284ba1 100644 (file)
@@ -987,7 +987,7 @@ static struct file_system_type ncp_fs_type = {
 static int __init init_ncp_fs(void)
 {
        int err;
-       DPRINTK("ncpfs: init_module called\n");
+       DPRINTK("ncpfs: init_ncp_fs called\n");
 
        err = init_inodecache();
        if (err)
@@ -1004,7 +1004,7 @@ out1:
 
 static void __exit exit_ncp_fs(void)
 {
-       DPRINTK("ncpfs: cleanup_module called\n");
+       DPRINTK("ncpfs: exit_ncp_fs called\n");
        unregister_filesystem(&ncp_fs_type);
        destroy_inodecache();
 }
index e6242cdbaf9198147d9b5225ac08cc8df630b001..fae97196daadb74c1dd1c28a5767460557402478 100644 (file)
@@ -96,7 +96,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
        inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
        if (IS_ERR(inode)) {
                dprintk("nfs_get_root: get root inode failed\n");
-               return ERR_PTR(PTR_ERR(inode));
+               return ERR_CAST(inode);
        }
 
        error = nfs_superblock_set_dummy_root(sb, inode);
@@ -266,7 +266,7 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
        inode = nfs_fhget(sb, mntfh, &fattr);
        if (IS_ERR(inode)) {
                dprintk("nfs_get_root: get root inode failed\n");
-               return ERR_PTR(PTR_ERR(inode));
+               return ERR_CAST(inode);
        }
 
        error = nfs_superblock_set_dummy_root(sb, inode);
index 79b4bf8129602b9ebbbec979960d614e90b7185b..346570f6d8481fa4b6b1593333d45a34abc3a824 100644 (file)
@@ -1218,13 +1218,13 @@ static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,
        struct svc_export *exp;
        struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
        if (IS_ERR(ek))
-               return ERR_PTR(PTR_ERR(ek));
+               return ERR_CAST(ek);
 
        exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
        cache_put(&ek->h, &svc_expkey_cache);
 
        if (IS_ERR(exp))
-               return ERR_PTR(PTR_ERR(exp));
+               return ERR_CAST(exp);
        return exp;
 }
 
index 6b7ff16189450b972374bfa0689f52e24a51405a..d17b4fd204e1f434558fdc55e78f6be0002a576e 100644 (file)
@@ -38,6 +38,8 @@ struct op_inode_info {
        union op_inode_data     u;
 };
 
+static struct inode *openprom_iget(struct super_block *sb, ino_t ino);
+
 static inline struct op_inode_info *OP_I(struct inode *inode)
 {
        return container_of(inode, struct op_inode_info, vfs_inode);
@@ -226,10 +228,10 @@ static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry
        return ERR_PTR(-ENOENT);
 
 found:
-       inode = iget(dir->i_sb, ino);
+       inode = openprom_iget(dir->i_sb, ino);
        mutex_unlock(&op_mutex);
-       if (!inode)
-               return ERR_PTR(-EINVAL);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
        ent_oi = OP_I(inode);
        ent_oi->type = ent_type;
        ent_oi->u = ent_data;
@@ -348,14 +350,23 @@ static void openprom_destroy_inode(struct inode *inode)
        kmem_cache_free(op_inode_cachep, OP_I(inode));
 }
 
-static void openprom_read_inode(struct inode * inode)
+static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
 {
-       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-       if (inode->i_ino == OPENPROM_ROOT_INO) {
-               inode->i_op = &openprom_inode_operations;
-               inode->i_fop = &openprom_operations;
-               inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+       struct inode *inode;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (inode->i_state & I_NEW) {
+               inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+               if (inode->i_ino == OPENPROM_ROOT_INO) {
+                       inode->i_op = &openprom_inode_operations;
+                       inode->i_fop = &openprom_operations;
+                       inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+               }
+               unlock_new_inode(inode);
        }
+       return inode;
 }
 
 static int openprom_remount(struct super_block *sb, int *flags, char *data)
@@ -367,7 +378,6 @@ static int openprom_remount(struct super_block *sb, int *flags, char *data)
 static const struct super_operations openprom_sops = {
        .alloc_inode    = openprom_alloc_inode,
        .destroy_inode  = openprom_destroy_inode,
-       .read_inode     = openprom_read_inode,
        .statfs         = simple_statfs,
        .remount_fs     = openprom_remount,
 };
@@ -376,6 +386,7 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent)
 {
        struct inode *root_inode;
        struct op_inode_info *oi;
+       int ret;
 
        s->s_flags |= MS_NOATIME;
        s->s_blocksize = 1024;
@@ -383,9 +394,11 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent)
        s->s_magic = OPENPROM_SUPER_MAGIC;
        s->s_op = &openprom_sops;
        s->s_time_gran = 1;
-       root_inode = iget(s, OPENPROM_ROOT_INO);
-       if (!root_inode)
+       root_inode = openprom_iget(s, OPENPROM_ROOT_INO);
+       if (IS_ERR(root_inode)) {
+               ret = PTR_ERR(root_inode);
                goto out_no_root;
+       }
 
        oi = OP_I(root_inode);
        oi->type = op_inode_node;
@@ -393,13 +406,15 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent)
 
        s->s_root = d_alloc_root(root_inode);
        if (!s->s_root)
-               goto out_no_root;
+               goto out_no_root_dentry;
        return 0;
 
+out_no_root_dentry:
+       iput(root_inode);
+       ret = -ENOMEM;
 out_no_root:
        printk("openprom_fill_super: get root inode failed\n");
-       iput(root_inode);
-       return -ENOMEM;
+       return ret;
 }
 
 static int openprom_get_sb(struct file_system_type *fs_type,
index a99acd8de3539ec56ecc9761a2bb37b66fcb7a93..cb5f0a3f1b035887acfafa9a0a5e4789dd9d8a33 100644 (file)
@@ -198,7 +198,7 @@ config LDM_DEBUG
 
 config SGI_PARTITION
        bool "SGI partition support" if PARTITION_ADVANCED
-       default y if (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM) && !CPU_LITTLE_ENDIAN))
+       default y if DEFAULT_SGI_PARTITION
        help
          Say Y here if you would like to be able to read the hard disk
          partition table format used by SGI machines.
index 89940f243fc235d2f2f8d9abf27e5b0f6862cd52..05ba692bc540ade3b63c5f5af72e1987556bd9fe 100644 (file)
@@ -83,6 +83,8 @@ void change_mnt_propagation(struct vfsmount *mnt, int type)
                mnt->mnt_master = NULL;
                if (type == MS_UNBINDABLE)
                        mnt->mnt_flags |= MNT_UNBINDABLE;
+               else
+                       mnt->mnt_flags &= ~MNT_UNBINDABLE;
        }
 }
 
index 1a551d92e1d8304b604946d5c16da8175fabe102..6ecf6396f0722e302c9108cd972624ff2cee290d 100644 (file)
@@ -73,11 +73,6 @@ static void proc_delete_inode(struct inode *inode)
 
 struct vfsmount *proc_mnt;
 
-static void proc_read_inode(struct inode * inode)
-{
-       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-}
-
 static struct kmem_cache * proc_inode_cachep;
 
 static struct inode *proc_alloc_inode(struct super_block *sb)
@@ -128,7 +123,6 @@ static int proc_remount(struct super_block *sb, int *flags, char *data)
 static const struct super_operations proc_sops = {
        .alloc_inode    = proc_alloc_inode,
        .destroy_inode  = proc_destroy_inode,
-       .read_inode     = proc_read_inode,
        .drop_inode     = generic_delete_inode,
        .delete_inode   = proc_delete_inode,
        .statfs         = simple_statfs,
@@ -401,39 +395,41 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
        if (de != NULL && !try_module_get(de->owner))
                goto out_mod;
 
-       inode = iget(sb, ino);
+       inode = iget_locked(sb, ino);
        if (!inode)
                goto out_ino;
-
-       PROC_I(inode)->fd = 0;
-       PROC_I(inode)->pde = de;
-       if (de) {
-               if (de->mode) {
-                       inode->i_mode = de->mode;
-                       inode->i_uid = de->uid;
-                       inode->i_gid = de->gid;
-               }
-               if (de->size)
-                       inode->i_size = de->size;
-               if (de->nlink)
-                       inode->i_nlink = de->nlink;
-               if (de->proc_iops)
-                       inode->i_op = de->proc_iops;
-               if (de->proc_fops) {
-                       if (S_ISREG(inode->i_mode)) {
+       if (inode->i_state & I_NEW) {
+               inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+               PROC_I(inode)->fd = 0;
+               PROC_I(inode)->pde = de;
+               if (de) {
+                       if (de->mode) {
+                               inode->i_mode = de->mode;
+                               inode->i_uid = de->uid;
+                               inode->i_gid = de->gid;
+                       }
+                       if (de->size)
+                               inode->i_size = de->size;
+                       if (de->nlink)
+                               inode->i_nlink = de->nlink;
+                       if (de->proc_iops)
+                               inode->i_op = de->proc_iops;
+                       if (de->proc_fops) {
+                               if (S_ISREG(inode->i_mode)) {
 #ifdef CONFIG_COMPAT
-                               if (!de->proc_fops->compat_ioctl)
-                                       inode->i_fop =
-                                               &proc_reg_file_ops_no_compat;
-                               else
+                                       if (!de->proc_fops->compat_ioctl)
+                                               inode->i_fop =
+                                                       &proc_reg_file_ops_no_compat;
+                                       else
 #endif
-                                       inode->i_fop = &proc_reg_file_ops;
+                                               inode->i_fop = &proc_reg_file_ops;
+                               } else {
+                                       inode->i_fop = de->proc_fops;
+                               }
                        }
-                       else
-                               inode->i_fop = de->proc_fops;
                }
+               unlock_new_inode(inode);
        }
-
        return inode;
 
 out_ino:
index 51288db37a0cf2e25ed2037b3e5161f6bc52a49e..2686592dbcb2b01b29108da7587361afce9fa6c3 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mm.h>
 #include <linux/mmzone.h>
 #include <linux/pagemap.h>
+#include <linux/interrupt.h>
 #include <linux/swap.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
@@ -64,7 +65,6 @@
  */
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
-extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
 extern int get_dma_list(char *);
 
@@ -84,10 +84,15 @@ static int loadavg_read_proc(char *page, char **start, off_t off,
 {
        int a, b, c;
        int len;
+       unsigned long seq;
+
+       do {
+               seq = read_seqbegin(&xtime_lock);
+               a = avenrun[0] + (FIXED_1/200);
+               b = avenrun[1] + (FIXED_1/200);
+               c = avenrun[2] + (FIXED_1/200);
+       } while (read_seqretry(&xtime_lock, seq));
 
-       a = avenrun[0] + (FIXED_1/200);
-       b = avenrun[1] + (FIXED_1/200);
-       c = avenrun[2] + (FIXED_1/200);
        len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
                LOAD_INT(a), LOAD_FRAC(a),
                LOAD_INT(b), LOAD_FRAC(b),
@@ -599,7 +604,6 @@ static void int_seq_stop(struct seq_file *f, void *v)
 }
 
 
-extern int show_interrupts(struct seq_file *f, void *v); /* In arch code */
 static struct seq_operations int_seq_ops = {
        .start = int_seq_start,
        .next  = int_seq_next,
index 638bdb963213bd70e2b0dab87f71cec1ce3d7f9f..b31ab78052b386380058e0fc9031f39f1fd1db63 100644 (file)
@@ -125,7 +125,6 @@ static int qnx4_write_inode(struct inode *inode, int unused)
 static void qnx4_put_super(struct super_block *sb);
 static struct inode *qnx4_alloc_inode(struct super_block *sb);
 static void qnx4_destroy_inode(struct inode *inode);
-static void qnx4_read_inode(struct inode *);
 static int qnx4_remount(struct super_block *sb, int *flags, char *data);
 static int qnx4_statfs(struct dentry *, struct kstatfs *);
 
@@ -133,7 +132,6 @@ static const struct super_operations qnx4_sops =
 {
        .alloc_inode    = qnx4_alloc_inode,
        .destroy_inode  = qnx4_destroy_inode,
-       .read_inode     = qnx4_read_inode,
        .put_super      = qnx4_put_super,
        .statfs         = qnx4_statfs,
        .remount_fs     = qnx4_remount,
@@ -357,6 +355,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
        struct inode *root;
        const char *errmsg;
        struct qnx4_sb_info *qs;
+       int ret = -EINVAL;
 
        qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
        if (!qs)
@@ -396,12 +395,14 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
        }
 
        /* does root not have inode number QNX4_ROOT_INO ?? */
-       root = iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
-       if (!root) {
+       root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
+       if (IS_ERR(root)) {
                printk("qnx4: get inode failed\n");
+               ret = PTR_ERR(root);
                goto out;
        }
 
+       ret = -ENOMEM;
        s->s_root = d_alloc_root(root);
        if (s->s_root == NULL)
                goto outi;
@@ -417,7 +418,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
       outnobh:
        kfree(qs);
        s->s_fs_info = NULL;
-       return -EINVAL;
+       return ret;
 }
 
 static void qnx4_put_super(struct super_block *sb)
@@ -462,29 +463,38 @@ static const struct address_space_operations qnx4_aops = {
        .bmap           = qnx4_bmap
 };
 
-static void qnx4_read_inode(struct inode *inode)
+struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
 {
        struct buffer_head *bh;
        struct qnx4_inode_entry *raw_inode;
-       int block, ino;
-       struct super_block *sb = inode->i_sb;
-       struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
+       int block;
+       struct qnx4_inode_entry *qnx4_inode;
+       struct inode *inode;
 
-       ino = inode->i_ino;
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       qnx4_inode = qnx4_raw_inode(inode);
        inode->i_mode = 0;
 
        QNX4DEBUG(("Reading inode : [%d]\n", ino));
        if (!ino) {
-               printk("qnx4: bad inode number on dev %s: %d is out of range\n",
+               printk(KERN_ERR "qnx4: bad inode number on dev %s: %lu is "
+                               "out of range\n",
                       sb->s_id, ino);
-               return;
+               iget_failed(inode);
+               return ERR_PTR(-EIO);
        }
        block = ino / QNX4_INODES_PER_BLOCK;
 
        if (!(bh = sb_bread(sb, block))) {
                printk("qnx4: major problem: unable to read inode from dev "
                       "%s\n", sb->s_id);
-               return;
+               iget_failed(inode);
+               return ERR_PTR(-EIO);
        }
        raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
            (ino % QNX4_INODES_PER_BLOCK);
@@ -515,9 +525,16 @@ static void qnx4_read_inode(struct inode *inode)
                inode->i_op = &page_symlink_inode_operations;
                inode->i_mapping->a_ops = &qnx4_aops;
                qnx4_i(inode)->mmu_private = inode->i_size;
-       } else
-               printk("qnx4: bad inode %d on dev %s\n",ino,sb->s_id);
+       } else {
+               printk(KERN_ERR "qnx4: bad inode %lu on dev %s\n",
+                       ino, sb->s_id);
+               iget_failed(inode);
+               brelse(bh);
+               return ERR_PTR(-EIO);
+       }
        brelse(bh);
+       unlock_new_inode(inode);
+       return inode;
 }
 
 static struct kmem_cache *qnx4_inode_cachep;
index 733cdf01d645365a204f57fbd83ddcdee292e608..775eed3a4085ffa793c7bd42ea1ad463a3c143f9 100644 (file)
@@ -128,10 +128,12 @@ struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nam
        }
        brelse(bh);
 
-       if ((foundinode = iget(dir->i_sb, ino)) == NULL) {
+       foundinode = qnx4_iget(dir->i_sb, ino);
+       if (IS_ERR(foundinode)) {
                unlock_kernel();
-               QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
-               return ERR_PTR(-EACCES);
+               QNX4DEBUG(("qnx4: lookup->iget -> error %ld\n",
+                          PTR_ERR(foundinode)));
+               return ERR_CAST(foundinode);
        }
 out:
        unlock_kernel();
index 99b24b52bfc83cbd8f851044dbe2ae27f8e1fc4b..84f28dd721163eb5ef09166bb3d96569c9724b6a 100644 (file)
@@ -341,11 +341,11 @@ static inline struct super_block *quotactl_block(const char __user *special)
        char *tmp = getname(special);
 
        if (IS_ERR(tmp))
-               return ERR_PTR(PTR_ERR(tmp));
+               return ERR_CAST(tmp);
        bdev = lookup_bdev(tmp);
        putname(tmp);
        if (IS_ERR(bdev))
-               return ERR_PTR(PTR_ERR(bdev));
+               return ERR_CAST(bdev);
        sb = get_super(bdev);
        bdput(bdev);
        if (!sb)
index 195309857e6323048e20b2286952e56b754b5301..57917932212eb33d68a0f626766c79fb608c442a 100644 (file)
@@ -1536,7 +1536,7 @@ static struct dentry *reiserfs_get_dentry(struct super_block *sb,
        if (!inode)
                inode = ERR_PTR(-ESTALE);
        if (IS_ERR(inode))
-               return ERR_PTR(PTR_ERR(inode));
+               return ERR_CAST(inode);
        result = d_alloc_anon(inode);
        if (!result) {
                iput(inode);
index 5e7388b32d020f17b6b22fb515bbe04a8a3ee67c..740bb8c0c1ae8e455caafadd37351a6d14b2815e 100644 (file)
@@ -575,6 +575,8 @@ void print_block(struct buffer_head *bh, ...)       //int print_mode, int first, int l
                                        printk
                                            ("Block %llu contains unformatted data\n",
                                             (unsigned long long)bh->b_blocknr);
+
+       va_end(args);
 }
 
 static char print_tb_buf[2048];
index 1597f6b649e040a5aad306e5cde5330f2e953f73..eba037b3338fe8c2c480318d38441d3de65aab51 100644 (file)
@@ -155,7 +155,7 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,
 
        xadir = open_xa_dir(inode, flags);
        if (IS_ERR(xadir)) {
-               return ERR_PTR(PTR_ERR(xadir));
+               return ERR_CAST(xadir);
        } else if (xadir && !xadir->d_inode) {
                dput(xadir);
                return ERR_PTR(-ENODATA);
@@ -164,7 +164,7 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,
        xafile = lookup_one_len(name, xadir, strlen(name));
        if (IS_ERR(xafile)) {
                dput(xadir);
-               return ERR_PTR(PTR_ERR(xafile));
+               return ERR_CAST(xafile);
        }
 
        if (xafile->d_inode) {  /* file exists */
@@ -1084,7 +1084,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
 }
 
 /* This is the implementation for the xattr plugin infrastructure */
-static struct list_head xattr_handlers = LIST_HEAD_INIT(xattr_handlers);
+static LIST_HEAD(xattr_handlers);
 static DEFINE_RWLOCK(handler_lock);
 
 static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
index a49cf5b9a195d32c51c7f077ea7b60cc7dc22cf8..00b6f0a518c87eab6d5382057d3e514e8d779f6b 100644 (file)
@@ -84,6 +84,8 @@ struct romfs_inode_info {
        struct inode vfs_inode;
 };
 
+static struct inode *romfs_iget(struct super_block *, unsigned long);
+
 /* instead of private superblock data */
 static inline unsigned long romfs_maxsize(struct super_block *sb)
 {
@@ -117,7 +119,7 @@ static int romfs_fill_super(struct super_block *s, void *data, int silent)
        struct buffer_head *bh;
        struct romfs_super_block *rsb;
        struct inode *root;
-       int sz;
+       int sz, ret = -EINVAL;
 
        /* I would parse the options here, but there are none.. :) */
 
@@ -157,10 +159,13 @@ static int romfs_fill_super(struct super_block *s, void *data, int silent)
             & ROMFH_MASK;
 
        s->s_op = &romfs_ops;
-       root = iget(s, sz);
-       if (!root)
+       root = romfs_iget(s, sz);
+       if (IS_ERR(root)) {
+               ret = PTR_ERR(root);
                goto out;
+       }
 
+       ret = -ENOMEM;
        s->s_root = d_alloc_root(root);
        if (!s->s_root)
                goto outiput;
@@ -173,7 +178,7 @@ outiput:
 out:
        brelse(bh);
 outnobh:
-       return -EINVAL;
+       return ret;
 }
 
 /* That's simple too. */
@@ -389,8 +394,11 @@ romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
        if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
                offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
 
-       if ((inode = iget(dir->i_sb, offset)))
-               goto outi;
+       inode = romfs_iget(dir->i_sb, offset);
+       if (IS_ERR(inode)) {
+               res = PTR_ERR(inode);
+               goto out;
+       }
 
        /*
         * it's a bit funky, _lookup needs to return an error code
@@ -402,7 +410,7 @@ romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
         */
 
 out0:  inode = NULL;
-outi:  res = 0;
+       res = 0;
        d_add (dentry, inode);
 
 out:   unlock_kernel();
@@ -478,20 +486,29 @@ static mode_t romfs_modemap[] =
        S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
 };
 
-static void
-romfs_read_inode(struct inode *i)
+static struct inode *
+romfs_iget(struct super_block *sb, unsigned long ino)
 {
-       int nextfh, ino;
+       int nextfh;
        struct romfs_inode ri;
+       struct inode *i;
+
+       ino &= ROMFH_MASK;
+       i = iget_locked(sb, ino);
+       if (!i)
+               return ERR_PTR(-ENOMEM);
+       if (!(i->i_state & I_NEW))
+               return i;
 
-       ino = i->i_ino & ROMFH_MASK;
        i->i_mode = 0;
 
        /* Loop for finding the real hard link */
        for(;;) {
                if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
-                       printk("romfs: read error for inode 0x%x\n", ino);
-                       return;
+                       printk(KERN_ERR "romfs: read error for inode 0x%lx\n",
+                               ino);
+                       iget_failed(i);
+                       return ERR_PTR(-EIO);
                }
                /* XXX: do romfs_checksum here too (with name) */
 
@@ -548,6 +565,8 @@ romfs_read_inode(struct inode *i)
                        init_special_inode(i, ino,
                                        MKDEV(nextfh>>16,nextfh&0xffff));
        }
+       unlock_new_inode(i);
+       return i;
 }
 
 static struct kmem_cache * romfs_inode_cachep;
@@ -599,7 +618,6 @@ static int romfs_remount(struct super_block *sb, int *flags, char *data)
 static const struct super_operations romfs_ops = {
        .alloc_inode    = romfs_alloc_inode,
        .destroy_inode  = romfs_destroy_inode,
-       .read_inode     = romfs_read_inode,
        .statfs         = romfs_statfs,
        .remount_fs     = romfs_remount,
 };
index 47f47925aea2bead2a4491d672476a7a63e9be1b..5633fe98078179b472a878c444594c4628dbde28 100644 (file)
@@ -739,7 +739,7 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
                        timeout_jiffies = -1;
                else
 #endif
-                       timeout_jiffies = msecs_to_jiffies(timeout_msecs);
+                       timeout_jiffies = msecs_to_jiffies(timeout_msecs) + 1;
        } else {
                /* Infinite (< 0) or no (0) timeout */
                timeout_jiffies = timeout_msecs;
index 2d3e107da2d3d009d49b505e1110c711f8d25112..cb2b63ae0bf40adc55ccde41d753e04097e1ddab 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/list.h>
 #include <linux/anon_inodes.h>
 #include <linux/signalfd.h>
+#include <linux/syscalls.h>
 
 struct signalfd_ctx {
        sigset_t sigmask;
index e48bd8235a8e39fd81231cb091ee570569d37b09..e37fe4deebd0ebe5050e1fbab7c9ef7cbc2ad4db 100644 (file)
@@ -329,9 +329,8 @@ smb_receive(struct smb_sb_info *server, struct smb_request *req)
        msg.msg_control = NULL;
 
        /* Dont repeat bytes and count available bufferspace */
-       rlen = smb_move_iov(&p, &num, iov, req->rq_bytes_recvd);
-       if (req->rq_rlen < rlen)
-               rlen = req->rq_rlen;
+       rlen = min_t(int, smb_move_iov(&p, &num, iov, req->rq_bytes_recvd),
+                       (req->rq_rlen - req->rq_bytes_recvd));
 
        result = kernel_recvmsg(sock, &msg, p, num, rlen, flags);
 
index 81ec6c548c07c0e34db7821cf72e8f0676f3d177..c5d60de0658f767cf91d13264c002bb9564d028a 100644 (file)
@@ -169,20 +169,27 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
                init_special_inode(inode, inode->i_mode, rdev);
 }
 
-static void sysv_read_inode(struct inode *inode)
+struct inode *sysv_iget(struct super_block *sb, unsigned int ino)
 {
-       struct super_block * sb = inode->i_sb;
        struct sysv_sb_info * sbi = SYSV_SB(sb);
        struct buffer_head * bh;
        struct sysv_inode * raw_inode;
        struct sysv_inode_info * si;
-       unsigned int block, ino = inode->i_ino;
+       struct inode *inode;
+       unsigned int block;
 
        if (!ino || ino > sbi->s_ninodes) {
                printk("Bad inode number on dev %s: %d is out of range\n",
-                      inode->i_sb->s_id, ino);
-               goto bad_inode;
+                      sb->s_id, ino);
+               return ERR_PTR(-EIO);
        }
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
        raw_inode = sysv_raw_inode(sb, ino, &bh);
        if (!raw_inode) {
                printk("Major problem: unable to read inode from dev %s\n",
@@ -214,11 +221,12 @@ static void sysv_read_inode(struct inode *inode)
                               old_decode_dev(fs32_to_cpu(sbi, si->i_data[0])));
        else
                sysv_set_inode(inode, 0);
-       return;
+       unlock_new_inode(inode);
+       return inode;
 
 bad_inode:
-       make_bad_inode(inode);
-       return;
+       iget_failed(inode);
+       return ERR_PTR(-EIO);
 }
 
 static struct buffer_head * sysv_update_inode(struct inode * inode)
@@ -328,7 +336,6 @@ static void init_once(struct kmem_cache *cachep, void *p)
 const struct super_operations sysv_sops = {
        .alloc_inode    = sysv_alloc_inode,
        .destroy_inode  = sysv_destroy_inode,
-       .read_inode     = sysv_read_inode,
        .write_inode    = sysv_write_inode,
        .delete_inode   = sysv_delete_inode,
        .put_super      = sysv_put_super,
index 6bd850b7641ae58bb1dd726c5ffb40fef0e0d595..a1f1ef33e81c4c5584a86630ca1bca637b078fea 100644 (file)
@@ -53,9 +53,9 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, st
        ino = sysv_inode_by_name(dentry);
 
        if (ino) {
-               inode = iget(dir->i_sb, ino);
-               if (!inode)
-                       return ERR_PTR(-EACCES);
+               inode = sysv_iget(dir->i_sb, ino);
+               if (IS_ERR(inode))
+                       return ERR_CAST(inode);
        }
        d_add(dentry, inode);
        return NULL;
index 6f9707a1b95438312b27a2e32e0bdcbf557244ac..5a903da5455154356b1b9d53bf28b3e0f8ae432d 100644 (file)
@@ -332,8 +332,8 @@ static int complete_read_super(struct super_block *sb, int silent, int size)
        sb->s_magic = SYSV_MAGIC_BASE + sbi->s_type;
        /* set up enough so that it can read an inode */
        sb->s_op = &sysv_sops;
-       root_inode = iget(sb,SYSV_ROOT_INO);
-       if (!root_inode || is_bad_inode(root_inode)) {
+       root_inode = sysv_iget(sb, SYSV_ROOT_INO);
+       if (IS_ERR(root_inode)) {
                printk("SysV FS: get root inode failed\n");
                return 0;
        }
index 64c03bdf06a5cf30a3dc7581be784f2c2b1c26f3..42d51d1c05cd418af8eeb0916fac5527ea99c258 100644 (file)
@@ -141,6 +141,7 @@ extern int __sysv_write_begin(struct file *file, struct address_space *mapping,
                        struct page **pagep, void **fsdata);
 
 /* inode.c */
+extern struct inode *sysv_iget(struct super_block *, unsigned int);
 extern int sysv_write_inode(struct inode *, int);
 extern int sysv_sync_inode(struct inode *);
 extern int sysv_sync_file(struct file *, struct dentry *, int);
index 4320782761ae875c54fc9f6a04592a3990ecfdc3..489f26bc26d9b4084b56b563761859186e1f9fd6 100644 (file)
@@ -714,26 +714,30 @@ static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode)
        return 0;
 }
 
-void ufs_read_inode(struct inode * inode)
+struct inode *ufs_iget(struct super_block *sb, unsigned long ino)
 {
-       struct ufs_inode_info *ufsi = UFS_I(inode);
-       struct super_block * sb;
-       struct ufs_sb_private_info * uspi;
+       struct ufs_inode_info *ufsi;
+       struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
        struct buffer_head * bh;
+       struct inode *inode;
        int err;
 
-       UFSD("ENTER, ino %lu\n", inode->i_ino);
-
-       sb = inode->i_sb;
-       uspi = UFS_SB(sb)->s_uspi;
+       UFSD("ENTER, ino %lu\n", ino);
 
-       if (inode->i_ino < UFS_ROOTINO ||
-           inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
+       if (ino < UFS_ROOTINO || ino > (uspi->s_ncg * uspi->s_ipg)) {
                ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n",
-                           inode->i_ino);
-               goto bad_inode;
+                           ino);
+               return ERR_PTR(-EIO);
        }
 
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       ufsi = UFS_I(inode);
+
        bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
        if (!bh) {
                ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n",
@@ -765,10 +769,12 @@ void ufs_read_inode(struct inode * inode)
        brelse(bh);
 
        UFSD("EXIT\n");
-       return;
+       unlock_new_inode(inode);
+       return inode;
 
 bad_inode:
-       make_bad_inode(inode);
+       iget_failed(inode);
+       return ERR_PTR(-EIO);
 }
 
 static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode)
index d8bfbee2fe2ba9e9ced1bcc66dbfdebb4b9ced7c..747a4de6c69526d14eaff5b48a08031d21d10d5d 100644 (file)
@@ -57,10 +57,10 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
        lock_kernel();
        ino = ufs_inode_by_name(dir, dentry);
        if (ino) {
-               inode = iget(dir->i_sb, ino);
-               if (!inode) {
+               inode = ufs_iget(dir->i_sb, ino);
+               if (IS_ERR(inode)) {
                        unlock_kernel();
-                       return ERR_PTR(-EACCES);
+                       return ERR_CAST(inode);
                }
        }
        unlock_kernel();
index 0072cb33ebec5da2f682574fbb36e809d0f1beb9..73deff475e6362326ab6e6785f89a93ad5b3f158 100644 (file)
@@ -633,6 +633,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        unsigned block_size, super_block_size;
        unsigned flags;
        unsigned super_block_offset;
+       int ret = -EINVAL;
 
        uspi = NULL;
        ubh = NULL;
@@ -1065,12 +1066,16 @@ magic_found:
                uspi->s_maxsymlinklen =
                    fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen);
 
-       inode = iget(sb, UFS_ROOTINO);
-       if (!inode || is_bad_inode(inode))
+       inode = ufs_iget(sb, UFS_ROOTINO);
+       if (IS_ERR(inode)) {
+               ret = PTR_ERR(inode);
                goto failed;
+       }
        sb->s_root = d_alloc_root(inode);
-       if (!sb->s_root)
+       if (!sb->s_root) {
+               ret = -ENOMEM;
                goto dalloc_failed;
+       }
 
        ufs_setup_cstotal(sb);
        /*
@@ -1092,7 +1097,7 @@ failed:
        kfree(sbi);
        sb->s_fs_info = NULL;
        UFSD("EXIT (FAILED)\n");
-       return -EINVAL;
+       return ret;
 
 failed_nomem:
        UFSD("EXIT (NOMEM)\n");
@@ -1326,7 +1331,6 @@ static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t,
 static const struct super_operations ufs_super_ops = {
        .alloc_inode    = ufs_alloc_inode,
        .destroy_inode  = ufs_destroy_inode,
-       .read_inode     = ufs_read_inode,
        .write_inode    = ufs_write_inode,
        .delete_inode   = ufs_delete_inode,
        .put_super      = ufs_put_super,
index 7faa4cd71a27537c9dac7ecf5e8c77aa1eb601c7..fcb9231bb9edac22b09593d8fa1d5e80624cde6a 100644 (file)
@@ -106,7 +106,7 @@ extern void ufs_free_inode (struct inode *inode);
 extern struct inode * ufs_new_inode (struct inode *, int);
 
 /* inode.c */
-extern void ufs_read_inode (struct inode *);
+extern struct inode *ufs_iget(struct super_block *, unsigned long);
 extern void ufs_put_inode (struct inode *);
 extern int ufs_write_inode (struct inode *, int);
 extern int ufs_sync_inode (struct inode *);
index b9912ecbee241231ca0b776d9131af1e2643d80a..e5588cd8530e1b7b751bb2a459ac51fdcd3498aa 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/utime.h>
+#include <linux/syscalls.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
index c28add2fbe95eebce0ec79de64e8389be793ea26..cd450bea9f1a179220364e9d42e48561a4d860a1 100644 (file)
@@ -705,7 +705,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
        brelse(sinfo.bh);
        if (IS_ERR(inode)) {
                unlock_kernel();
-               return ERR_PTR(PTR_ERR(inode));
+               return ERR_CAST(inode);
        }
        alias = d_find_alias(inode);
        if (alias) {
index 4b518e3b952c2e607993d4e5ebf0b64c01b83d14..fc1002ea1e0c766c5150e633d1a83dfa7700a17f 100644 (file)
@@ -144,8 +144,6 @@ extern int dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task);
        : amask (AMASK_CIX) ? "ev6" : "ev67");  \
 })
 
-#ifdef __KERNEL__
-
 #define SET_PERSONALITY(EX, IBCS2)                             \
        set_personality(((EX).e_flags & EF_ALPHA_32BIT)         \
           ? PER_LINUX_32BIT : (IBCS2) ? PER_SVR4 : PER_LINUX)
@@ -164,5 +162,4 @@ extern int alpha_l3_cacheshape;
     NEW_AUX_ENT(AT_L3_CACHESHAPE, alpha_l3_cacheshape);                \
   } while (0)
 
-#endif /* __KERNEL__ */
 #endif /* __ASM_ALPHA_ELF_H */
index 8cc97bfd37893583e850b26f9fbd1f1b24265dc7..05f09f997d829429f0ece5af420105299997afd0 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _ALPHA_PAGE_H
 #define _ALPHA_PAGE_H
 
-#ifdef __KERNEL__
-
 #include <linux/const.h>
 #include <asm/pal.h>
 
@@ -98,5 +96,4 @@ typedef unsigned long pgprot_t;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
 #endif /* _ALPHA_PAGE_H */
index fd9dc889f36c87b55da179ba39f3528e6cf8e1cb..ed221d6408fc308acbf737d84ba51adb9899dc28 100644 (file)
@@ -681,13 +681,18 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
        return old;
 }
 
-#define cmpxchg(ptr,o,n)                                                \
+#define cmpxchg(ptr, o, n)                                              \
   ({                                                                    \
      __typeof__(*(ptr)) _o_ = (o);                                      \
      __typeof__(*(ptr)) _n_ = (n);                                      \
      (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,          \
                                    (unsigned long)_n_, sizeof(*(ptr))); \
   })
+#define cmpxchg64(ptr, o, n)                                            \
+  ({                                                                    \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                               \
+       cmpxchg((ptr), (o), (n));                                        \
+  })
 
 static inline unsigned long
 __cmpxchg_u8_local(volatile char *m, long old, long new)
@@ -803,13 +808,19 @@ __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
        return old;
 }
 
-#define cmpxchg_local(ptr,o,n)                                          \
+#define cmpxchg_local(ptr, o, n)                                        \
   ({                                                                    \
      __typeof__(*(ptr)) _o_ = (o);                                      \
      __typeof__(*(ptr)) _n_ = (n);                                      \
      (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,    \
                                    (unsigned long)_n_, sizeof(*(ptr))); \
   })
+#define cmpxchg64_local(ptr, o, n)                                      \
+  ({                                                                    \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                               \
+       cmpxchg_local((ptr), (o), (n));                                  \
+  })
+
 
 #endif /* __ASSEMBLY__ */
 
index 7e417fc9d4916a0f91f9799686f9fa307a9cfe61..a4eb6a4ca8d19b19724be4a02ebb58a13da54459 100644 (file)
@@ -39,7 +39,7 @@ struct user {
        unsigned long   start_data;             /* data starting address */
        unsigned long   start_stack;            /* stack starting address */
        long int        signal;                 /* signal causing core dump */
-       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   u_ar0;                  /* help gdb find registers */
        unsigned long   magic;                  /* identifies a core file */
        char            u_comm[32];             /* user command name */
 };
index 04006c1c5fd76bb75387b3136fc1e62619617b1c..efd9a5eb10081275859eb5605e78611f149572da 100644 (file)
@@ -247,7 +247,7 @@ static inline u32 iop_desc_get_src_count(struct iop_adma_desc_slot *desc,
 }
 
 static inline void
-iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, unsigned long flags)
 {
        struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
        union {
@@ -257,13 +257,13 @@ iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
 
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->crc_addr = 0;
 }
 
 static inline void
-iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memset(struct iop_adma_desc_slot *desc, unsigned long flags)
 {
        struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
        union {
@@ -274,14 +274,15 @@ iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
        u_desc_ctrl.field.block_fill_en = 1;
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->crc_addr = 0;
 }
 
 /* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */
 static inline void
-iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt,
+                 unsigned long flags)
 {
        struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
        union {
@@ -292,7 +293,7 @@ iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.src_select = src_cnt - 1;
        u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->crc_addr = 0;
 
@@ -301,7 +302,8 @@ iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
 
 /* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */
 static inline int
-iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt,
+                      unsigned long flags)
 {
        struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
        union {
@@ -314,7 +316,7 @@ iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
        u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
        u_desc_ctrl.field.zero_result = 1;
        u_desc_ctrl.field.status_write_back_en = 1;
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->crc_addr = 0;
 
index 76fe5f6934267f702341b80ebba58ac7c3857c34..bd854845697f314c11af21af0ae537cf43b0b661 100644 (file)
 
 #define S3C2412_FRCPAT(x)      S3C2410_LCDREG(0xB4 + ((x)*4))
 
-#endif /* ___ASM_ARCH_REGS_LCD_H */
+/* general registers */
+
+/* base of the LCD registers, where INTPND, INTSRC and then INTMSK
+ * are available. */
 
+#define S3C2410_LCDINTBASE     S3C2410_LCDREG(0x54)
+#define S3C2412_LCDINTBASE     S3C2410_LCDREG(0x24)
 
+#define S3C24XX_LCDINTPND      (0x00)
+#define S3C24XX_LCDSRCPND      (0x04)
+#define S3C24XX_LCDINTMSK      (0x08)
 
+#endif /* ___ASM_ARCH_REGS_LCD_H */
index ba1dca88d48069dcb59040001b796c4b6c24399e..73803731142a6928bc44127d506210a61ff79db4 100644 (file)
@@ -13,9 +13,6 @@
 #ifndef __ASM_ARCH_SPIGPIO_H
 #define __ASM_ARCH_SPIGPIO_H __FILE__
 
-struct s3c2410_spigpio_info;
-struct spi_board_info;
-
 struct s3c2410_spigpio_info {
        unsigned long            pin_clk;
        unsigned long            pin_mosi;
@@ -23,9 +20,6 @@ struct s3c2410_spigpio_info {
 
        int                      bus_num;
 
-       unsigned long            board_size;
-       struct spi_board_info   *board_info;
-
        void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
 };
 
index 4029a1a1ab406fcaf661f94c8243f15d0269f8c0..7ca0ed97a6d0fd7e457c8b9549ba98c98dbf28b4 100644 (file)
 #ifndef __ASM_ARCH_SPI_H
 #define __ASM_ARCH_SPI_H __FILE__
 
-struct s3c2410_spi_info;
-struct spi_board_info;
-
 struct s3c2410_spi_info {
        unsigned long            pin_cs;        /* simple gpio cs */
 
-       unsigned long            board_size;
-       struct spi_board_info   *board_info;
-
        void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
 };
 
index ec1c685562ce2ec19366c4e93cc1c6988a1cf5f3..4ca7516274898dafae96518f76a4f6656a352264 100644 (file)
@@ -41,7 +41,6 @@ typedef struct user_fp elf_fpregset_t;
 #endif
 #define ELF_ARCH       EM_ARM
 
-#ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 /*
  * This yields a string that ld.so will use to load implementation
@@ -115,5 +114,3 @@ extern char elf_platform[];
        } while (0)
 
 #endif
-
-#endif
index 10834b54f6816c49431ab5de7b952e7bd2114e08..5c529e6a5e3b6a7c0336ca0b6a205887fb443f55 100644 (file)
@@ -414,7 +414,7 @@ static inline void iop3xx_aau_desc_set_src_addr(struct iop3xx_desc_aau *hw_desc,
 }
 
 static inline void
-iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, unsigned long flags)
 {
        struct iop3xx_desc_dma *hw_desc = desc->hw_desc;
        union {
@@ -425,14 +425,14 @@ iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.mem_to_mem_en = 1;
        u_desc_ctrl.field.pci_transaction = 0xe; /* memory read block */
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->upper_pci_src_addr = 0;
        hw_desc->crc_addr = 0;
 }
 
 static inline void
-iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memset(struct iop_adma_desc_slot *desc, unsigned long flags)
 {
        struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
        union {
@@ -443,12 +443,13 @@ iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.blk1_cmd_ctrl = 0x2; /* memory block fill */
        u_desc_ctrl.field.dest_write_en = 1;
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
 }
 
 static inline u32
-iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt, int int_en)
+iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt,
+                    unsigned long flags)
 {
        int i, shift;
        u32 edcr;
@@ -509,21 +510,23 @@ iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt, int int_en)
 
        u_desc_ctrl.field.dest_write_en = 1;
        u_desc_ctrl.field.blk1_cmd_ctrl = 0x7; /* direct fill */
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
 
        return u_desc_ctrl.value;
 }
 
 static inline void
-iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt,
+                 unsigned long flags)
 {
-       iop3xx_desc_init_xor(desc->hw_desc, src_cnt, int_en);
+       iop3xx_desc_init_xor(desc->hw_desc, src_cnt, flags);
 }
 
 /* return the number of operations */
 static inline int
-iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt,
+                      unsigned long flags)
 {
        int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op;
        struct iop3xx_desc_aau *hw_desc, *prev_hw_desc, *iter;
@@ -538,10 +541,10 @@ iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
        for (i = 0, j = 0; (slot_cnt -= slots_per_op) >= 0;
                i += slots_per_op, j++) {
                iter = iop_hw_desc_slot_idx(hw_desc, i);
-               u_desc_ctrl.value = iop3xx_desc_init_xor(iter, src_cnt, int_en);
+               u_desc_ctrl.value = iop3xx_desc_init_xor(iter, src_cnt, flags);
                u_desc_ctrl.field.dest_write_en = 0;
                u_desc_ctrl.field.zero_result_en = 1;
-               u_desc_ctrl.field.int_en = int_en;
+               u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
                iter->desc_ctrl = u_desc_ctrl.value;
 
                /* for the subsequent descriptors preserve the store queue
@@ -559,7 +562,8 @@ iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
 }
 
 static inline void
-iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt,
+                      unsigned long flags)
 {
        struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
        union {
@@ -591,7 +595,7 @@ iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
        }
 
        u_desc_ctrl.field.dest_write_en = 0;
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
 }
 
index 7e85db77d99b12f635514a7c84e9b8c713064af4..31ff12f4ffb7b5fdb757767a159c4f855c544630 100644 (file)
@@ -10,9 +10,6 @@
 #ifndef _ASMARM_PAGE_H
 #define _ASMARM_PAGE_H
 
-
-#ifdef __KERNEL__
-
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT             12
 #define PAGE_SIZE              (1UL << PAGE_SHIFT)
@@ -192,6 +189,4 @@ typedef unsigned long pgprot_t;
 
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
-
 #endif
index 28425c473e71c72c7a959f6650fc6707a89d6b0e..6335de9a2bb384b5f8b6f83fdd832402e123eb89 100644 (file)
@@ -363,6 +363,21 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern void disable_hlt(void);
 extern void enable_hlt(void);
 
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #define arch_align_stack(x) (x)
index 3e8b0f87915935565e78e684416159d265b59d1b..825c1e7c582d9adef9263c1135754bb1d1f5ae5e 100644 (file)
@@ -67,7 +67,7 @@ struct user{
                                   esp register.  */
   long int signal;                     /* Signal that caused the core dump. */
   int reserved;                        /* No longer used */
-  struct pt_regs * u_ar0;      /* Used by gdb to help find the values for */
+  unsigned long u_ar0;         /* Used by gdb to help find the values for */
                                /* the registers. */
   unsigned long magic;         /* To uniquely identify a core file */
   char u_comm[32];             /* User command that was responsible */
index cc3b2e3343b35d3e16321086005a9c9fd7cc4078..a0ed9a9839a54f2982468da7e0ade766d5176343 100644 (file)
@@ -12,7 +12,7 @@ extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
 extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
 extern void __delay(unsigned long loops);
 
 #define udelay(n) (__builtin_constant_p(n) ? \
index d334b4994d2d4e8da6fad1aa79e42f4bb600cf27..64ce40ee1d585d052e437d4f8ada3026e200bcfb 100644 (file)
@@ -103,8 +103,6 @@ typedef struct user_fpu_struct elf_fpregset_t;
 
 #define ELF_PLATFORM  (NULL)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
-#endif
 
 #endif /* __ASM_AVR32_ELF_H */
index 0f630b3e9932f5fd4991366b08f0829167da0168..ee23499cec34df071b4c6a75ae189ed08797f7df 100644 (file)
@@ -8,8 +8,6 @@
 #ifndef __ASM_AVR32_PAGE_H
 #define __ASM_AVR32_PAGE_H
 
-#ifdef __KERNEL__
-
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT     12
 #ifdef __ASSEMBLY__
@@ -107,6 +105,4 @@ static inline int get_order(unsigned long size)
  */
 #define HIGHMEM_START          0x20000000UL
 
-#endif /* __KERNEL__ */
-
 #endif /* __ASM_AVR32_PAGE_H */
index c600cc15cbcb640d2d7941f0991fb823dd8fd2f4..9702c2213e1e74d979fb914b286cfbfac8c1609d 100644 (file)
@@ -145,6 +145,29 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
                                   (unsigned long)(new),        \
                                   sizeof(*(ptr))))
 
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+                                     unsigned long old,
+                                     unsigned long new, int size)
+{
+       switch (size) {
+       case 4:
+               return __cmpxchg_u32(ptr, old, new);
+       default:
+               return __cmpxchg_local_generic(ptr, old, new, size);
+       }
+
+       return old;
+}
+
+#define cmpxchg_local(ptr, old, new)                                   \
+       ((typeof(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(old),   \
+                                  (unsigned long)(new),                \
+                                  sizeof(*(ptr))))
+
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
 struct pt_regs;
 void NORET_TYPE die(const char *str, struct pt_regs *regs, long err);
 void _exception(long signr, struct pt_regs *regs, int code,
index 5e44ecb3ce0cf63cc97a348227464a05312f66b8..187dcf38b2104e911b39014a458b575e1f6719fe 100644 (file)
@@ -34,7 +34,6 @@ static inline cycles_t get_cycles (void)
        return 0;
 }
 
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER    1
+#define ARCH_HAS_READ_CURRENT_TIMER
 
 #endif /* __ASM_AVR32_TIMEX_H */
index 060fb3acee49573fe791276391f722872505f528..7e9152f81f5e9ec4a2f9dd3bdd89bb387702d38b 100644 (file)
@@ -51,7 +51,7 @@ struct user {
        unsigned long   start_data;             /* data starting address */
        unsigned long   start_stack;            /* stack starting address */
        long int        signal;                 /* signal causing core dump */
-       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   u_ar0;                  /* help gdb find registers */
        unsigned long   magic;                  /* identifies a core file */
        char            u_comm[32];             /* user command name */
 };
index 5264b5536a70b4887e21b68cc93d4a65424cf3e7..30303fc8292c3ac820653e83d36f520141d40c91 100644 (file)
@@ -120,8 +120,6 @@ do {                                                                                        \
 
 #define ELF_PLATFORM  (NULL)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
-#endif
 
 #endif
index 1601d62f39a57785a925d6e2ca3a260a5bd9cabe..574fe56989d1d68c82e90ef6d1d365720a7ce162 100644 (file)
@@ -188,8 +188,6 @@ extern void blkfin_inv_cache_all(void);
 #define page_to_phys(page)      ((page - mem_map) << PAGE_SHIFT)
 #define page_to_bus(page)       ((page - mem_map) << PAGE_SHIFT)
 
-#define mm_ptov(vaddr)         ((void *) (vaddr))
-#define mm_vtop(vaddr)         ((unsigned long) (vaddr))
 #define phys_to_virt(vaddr)    ((void *) (vaddr))
 #define virt_to_phys(vaddr)    ((unsigned long) (vaddr))
 
index 8bc86717021c111452337c3812f259c8985129fa..d5c9d1433781233e75871debc2bdebdfaf994b17 100644 (file)
@@ -11,8 +11,6 @@
 #endif
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
-#ifdef __KERNEL__
-
 #include <asm/setup.h>
 
 #ifndef __ASSEMBLY__
@@ -88,6 +86,5 @@ extern unsigned long memory_end;
 #include <asm-generic/page.h>
 
 #endif                         /* __ASSEMBLY__ */
-#endif                         /* __KERNEL__ */
 
 #endif                         /* _BLACKFIN_PAGE_H */
index 4a927379ee1ce9c5fdc006fe2a3bbed851f3d1eb..51494ef5bb411759c12c2db6ab69dc6d3dfbd796 100644 (file)
@@ -183,55 +183,20 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
        return tmp;
 }
 
+#include <asm-generic/cmpxchg-local.h>
+
 /*
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
  */
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-                                     unsigned long new, int size)
-{
-       unsigned long tmp = 0;
-       unsigned long flags = 0;
-
-       local_irq_save(flags);
-
-       switch (size) {
-       case 1:
-               __asm__ __volatile__
-                       ("%0 = b%3 (z);\n\t"
-                        "CC = %1 == %0;\n\t"
-                        "IF !CC JUMP 1f;\n\t"
-                        "b%3 = %2;\n\t"
-                        "1:\n\t"
-                        : "=&d" (tmp) : "d" (old), "d" (new), "m" (*__xg(ptr)) : "memory");
-               break;
-       case 2:
-               __asm__ __volatile__
-                       ("%0 = w%3 (z);\n\t"
-                        "CC = %1 == %0;\n\t"
-                        "IF !CC JUMP 1f;\n\t"
-                        "w%3 = %2;\n\t"
-                        "1:\n\t"
-                        : "=&d" (tmp) : "d" (old), "d" (new), "m" (*__xg(ptr)) : "memory");
-               break;
-       case 4:
-               __asm__ __volatile__
-                       ("%0 = %3;\n\t"
-                        "CC = %1 == %0;\n\t"
-                        "IF !CC JUMP 1f;\n\t"
-                        "%3 = %2;\n\t"
-                        "1:\n\t"
-                        : "=&d" (tmp) : "d" (old), "d" (new), "m" (*__xg(ptr)) : "memory");
-               break;
-       }
-       local_irq_restore(flags);
-       return tmp;
-}
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
-#define cmpxchg(ptr,o,n)\
-        ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
-                                        (unsigned long)(n),sizeof(*(ptr))))
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
 
 #define prepare_to_switch()     do { } while(0)
 
index abc34629bd59aad786d8578976a7a3c4d903aefd..afe6a0e1f7cef107767f111bd732df75bfd458b3 100644 (file)
@@ -75,7 +75,7 @@ struct user {
                                           esp register.  */
        long int signal;        /* Signal that caused the core dump. */
        int reserved;           /* No longer used */
-       struct user_regs_struct *u_ar0;
+       unsigned long u_ar0;
        /* Used by gdb to help find the values for */
        /* the registers. */
        unsigned long magic;    /* To uniquely identify a core file */
index 96a40c1de57c460238688258b744e628cb00ddde..001f64ad11e8c5e002003427b6833c402a3f26d7 100644 (file)
@@ -45,7 +45,6 @@ typedef unsigned long elf_fpregset_t;
 #define ELF_DATA       ELFDATA2LSB
 #define ELF_ARCH       EM_CRIS
 
-#ifdef __KERNEL__
 #include <asm/arch/elf.h>
 
 /* The master for these definitions is {binutils}/include/elf/cris.h:  */
@@ -91,6 +90,4 @@ typedef unsigned long elf_fpregset_t;
 
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 
-#endif /* __KERNEL__ */
-
 #endif
index b84353ef6998459ccf3b40da3777254cadcfe1fe..3b0156c4631107dc91dc13dd86468f2dff2c91ca 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _CRIS_PAGE_H
 #define _CRIS_PAGE_H
 
-#ifdef __KERNEL__
-
 #include <asm/arch/page.h>
 #include <linux/const.h>
 
@@ -74,7 +72,5 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _CRIS_PAGE_H */
 
index fea0e8d57cb51883f5d0c31202ef33ed089f863d..5bcfe5a1090765e7359c4f64f0de4001597f3241 100644 (file)
@@ -66,6 +66,21 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
   return x;
 }
 
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
 #define arch_align_stack(x) (x)
 
 void default_idle(void);
index 2538e2a003df3ddc456be77bbf427f35c813fe00..73e60fcbcf38dc87ca8f0df56f7f8b92555d1a95 100644 (file)
@@ -38,7 +38,7 @@ struct user {
        unsigned long   start_data;             /* data starting address */
        unsigned long   start_stack;            /* stack starting address */
        long int        signal;                 /* signal causing core dump */
-       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   u_ar0;                  /* help gdb find registers */
        unsigned long   magic;                  /* identifies a core file */
        char            u_comm[32];             /* user command name */
 };
index 966a9836d556a520afebaea42a613849a6d46e01..bc3f12c5b7e05688a609350735ab44744fa4b6f8 100644 (file)
@@ -4,4 +4,3 @@ header-y += registers.h
 
 unifdef-y += termios.h
 unifdef-y += ptrace.h
-unifdef-y += page.h
index 7df58a3e6e4a5537e69ea2fb97cc1be4c16c7368..9fb946bb7dc98c26cc8b43b2e3686647238e0d86 100644 (file)
@@ -137,8 +137,6 @@ do {                                                                                        \
 
 #define ELF_PLATFORM  (NULL)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
-#endif
 
 #endif
index bd9bd2d9cc7894294c737fa9fe4a2871050030a8..cacc045700de98eb36f156738cb12b2c24f0ad36 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _ASM_PAGE_H
 #define _ASM_PAGE_H
 
-#ifdef __KERNEL__
-
 #include <asm/virtconvert.h>
 #include <asm/mem-layout.h>
 #include <asm/sections.h>
@@ -79,6 +77,4 @@ extern unsigned long max_pfn;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_PAGE_H */
index 9f5663ba19f8eaad3ee4680d81894b18b1748ba0..59be5443a68f23cead7a8517f29ad2380b44bb84 100644 (file)
@@ -268,5 +268,29 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
 
 #endif
 
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+                                     unsigned long old,
+                                     unsigned long new, int size)
+{
+       switch (size) {
+       case 4:
+               return cmpxchg(ptr, old, new);
+       default:
+               return __cmpxchg_local_generic(ptr, old, new, size);
+       }
+
+       return old;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                       \
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
 #endif /* _ASM_SYSTEM_H */
index 8fd81713cfc0cd68ca2f6fca85282f1892cdd632..57ba6063595914a8021b38d923b23763da80ab5f 100644 (file)
@@ -27,8 +27,3 @@ unifdef-y += termbits.h
 unifdef-y += termios.h
 unifdef-y += types.h
 unifdef-y += unistd.h
-unifdef-y += user.h
-
-# These probably shouldn't be exported
-unifdef-y += elf.h
-unifdef-y += page.h
diff --git a/include/asm-generic/cmpxchg-local.h b/include/asm-generic/cmpxchg-local.h
new file mode 100644 (file)
index 0000000..b2ba2fc
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef __ASM_GENERIC_CMPXCHG_LOCAL_H
+#define __ASM_GENERIC_CMPXCHG_LOCAL_H
+
+#include <linux/types.h>
+
+extern unsigned long wrong_size_cmpxchg(volatile void *ptr);
+
+/*
+ * Generic version of __cmpxchg_local (disables interrupts). Takes an unsigned
+ * long parameter, supporting various types of architectures.
+ */
+static inline unsigned long __cmpxchg_local_generic(volatile void *ptr,
+               unsigned long old, unsigned long new, int size)
+{
+       unsigned long flags, prev;
+
+       /*
+        * Sanity checking, compile-time.
+        */
+       if (size == 8 && sizeof(unsigned long) != 8)
+               wrong_size_cmpxchg(ptr);
+
+       local_irq_save(flags);
+       switch (size) {
+       case 1: prev = *(u8 *)ptr;
+               if (prev == old)
+                       *(u8 *)ptr = (u8)new;
+               break;
+       case 2: prev = *(u16 *)ptr;
+               if (prev == old)
+                       *(u16 *)ptr = (u16)new;
+               break;
+       case 4: prev = *(u32 *)ptr;
+               if (prev == old)
+                       *(u32 *)ptr = (u32)new;
+               break;
+       case 8: prev = *(u64 *)ptr;
+               if (prev == old)
+                       *(u64 *)ptr = (u64)new;
+               break;
+       default:
+               wrong_size_cmpxchg(ptr);
+       }
+       local_irq_restore(flags);
+       return prev;
+}
+
+/*
+ * Generic version of __cmpxchg64_local. Takes an u64 parameter.
+ */
+static inline u64 __cmpxchg64_local_generic(volatile void *ptr,
+               u64 old, u64 new)
+{
+       u64 prev;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       prev = *(u64 *)ptr;
+       if (prev == old)
+               *(u64 *)ptr = new;
+       local_irq_restore(flags);
+       return prev;
+}
+
+#endif
diff --git a/include/asm-generic/cmpxchg.h b/include/asm-generic/cmpxchg.h
new file mode 100644 (file)
index 0000000..213ac6e
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __ASM_GENERIC_CMPXCHG_H
+#define __ASM_GENERIC_CMPXCHG_H
+
+/*
+ * Generic cmpxchg
+ *
+ * Uses the local cmpxchg. Does not support SMP.
+ */
+#ifdef CONFIG_SMP
+#error "Cannot use generic cmpxchg on SMP"
+#endif
+
+/*
+ * Atomic compare and exchange.
+ *
+ * Do not define __HAVE_ARCH_CMPXCHG because we want to use it to check whether
+ * a cmpxchg primitive faster than repeated local irq save/restore exists.
+ */
+#define cmpxchg(ptr, o, n)     cmpxchg_local((ptr), (o), (n))
+#define cmpxchg64(ptr, o, n)   cmpxchg64_local((ptr), (o), (n))
+
+#endif
index 09204e40d66312edb7ba12e58261fd4760a89939..1c1fa422d18ab0dea14dbd7fc1e2d3b4731d7d76 100644 (file)
@@ -18,6 +18,7 @@ typedef unsigned long cputime_t;
 #define cputime_lt(__a, __b)           ((__a) <  (__b))
 #define cputime_le(__a, __b)           ((__a) <= (__b))
 #define cputime_to_jiffies(__ct)       (__ct)
+#define cputime_to_scaled(__ct)                (__ct)
 #define jiffies_to_cputime(__hz)       (__hz)
 
 typedef u64 cputime64_t;
index 962cad7cfbbda0849cc68380b43c2da97643f23c..8feeae1f2369b64cdf1be263880200503c5c3a41 100644 (file)
@@ -8,8 +8,6 @@ extern char _data[], _sdata[], _edata[];
 extern char __bss_start[], __bss_stop[];
 extern char __init_begin[], __init_end[];
 extern char _sinittext[], _einittext[];
-extern char _sextratext[] __attribute__((weak));
-extern char _eextratext[] __attribute__((weak));
 extern char _end[];
 extern char __per_cpu_start[], __per_cpu_end[];
 extern char __kprobes_text_start[], __kprobes_text_end[];
index 7ba6a0af447c6196165f4a85fde10a819043ac98..26bfc7e641daf339b933c269526b98e984734120 100644 (file)
@@ -55,9 +55,7 @@ typedef unsigned long elf_fpregset_t;
 
 #define ELF_PLATFORM  (NULL)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX)
-#endif
 
 #define R_H8_NONE       0
 #define R_H8_DIR32      1
index 7543a57b4ea13dce3ba67355eb161f8b14ce305f..26dc6ccd9441a2237ada1f7168131f07402949a9 100644 (file)
@@ -302,8 +302,6 @@ static __inline__ void ctrl_outl(unsigned long b, unsigned long addr)
 /*
  * Macros used for converting between virtual and physical mappings.
  */
-#define mm_ptov(vaddr)         ((void *) (vaddr))
-#define mm_vtop(vaddr)         ((unsigned long) (vaddr))
 #define phys_to_virt(vaddr)    ((void *) (vaddr))
 #define virt_to_phys(vaddr)    ((unsigned long) (vaddr))
 
index c8cc81a3aca52619e0670634332775b9739e6d5c..a83492449130eb994a650ddb6b986e180aa298c6 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _H8300_PAGE_H
 #define _H8300_PAGE_H
 
-#ifdef __KERNEL__
-
 /* PAGE_SHIFT determines the page size */
 
 #define PAGE_SHIFT     (12)
@@ -79,6 +77,4 @@ extern unsigned long memory_end;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _H8300_PAGE_H */
index 2c1e83f7b4191568bcb1880cc5f423c7bdaa3773..4b8e475908ae0c9eab94c5ac55cb7e2c36216000 100644 (file)
@@ -138,6 +138,21 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
         asm("jmp @@0");                        \
 })
 
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
 #define arch_align_stack(x) (x)
 
 #endif /* _H8300_SYSTEM_H */
index 6c64f99af3e1566d2396dc4326a6a3827dd34047..14a9e18950f166384186d0eaa18a0984c4ac8f12 100644 (file)
@@ -62,8 +62,7 @@ struct user{
                                   esp register.  */
   long int signal;                     /* Signal that caused the core dump. */
   int reserved;                        /* No longer used */
-  struct user_regs_struct *u_ar0;
-                               /* Used by gdb to help find the values for */
+  unsigned long u_ar0;         /* Used by gdb to help find the values for */
                                /* the registers. */
   unsigned long magic;         /* To uniquely identify a core file */
   char u_comm[32];             /* User command that was responsible */
index ee7d5ea10065dc3ba28a7d9d9f8c5ca0724b8993..19cfd62b11c30ac1206a0f9b4fc61f21fc1efdb5 100644 (file)
@@ -10,8 +10,6 @@
 #include <asm/setup.h>
 #include <asm/page.h>
 
-#define mm_ptov(vaddr)         ((void *) (vaddr))
-#define mm_vtop(vaddr)         ((unsigned long) (vaddr))
 #define phys_to_virt(vaddr)    ((void *) (vaddr))
 #define virt_to_phys(vaddr)    ((unsigned long) (vaddr))
 
index f10e29b60b0010b322b3aec2242b3dfb6a5de66e..f8e83eca67a2a4888bd281a8365fbf9607074e9f 100644 (file)
@@ -177,7 +177,6 @@ extern void ia64_elf_core_copy_regs (struct pt_regs *src, elf_gregset_t dst);
    relevant until we have real hardware to play with... */
 #define ELF_PLATFORM   NULL
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2)     set_personality(PER_LINUX)
 #define elf_read_implies_exec(ex, executable_stack)                                    \
        ((executable_stack!=EXSTACK_DISABLE_X) && ((ex).e_flags & EF_IA_64_LINUX_EXECUTABLE_STACK) != 0)
@@ -248,6 +247,4 @@ do {                                                                        \
        }                                                               \
 } while (0)
 
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_IA64_ELF_H */
index 3a95aa432e99f839dc94da7ae0b2786629a8cbcf..f1135b5b94c3df8483f8fc2af0ec32f07b563130 100644 (file)
@@ -153,11 +153,17 @@ extern long ia64_cmpxchg_called_with_bad_pointer (void);
        (__typeof__(old)) _r_;                                                          \
 })
 
-#define cmpxchg_acq(ptr,o,n)   ia64_cmpxchg(acq, (ptr), (o), (n), sizeof(*(ptr)))
-#define cmpxchg_rel(ptr,o,n)   ia64_cmpxchg(rel, (ptr), (o), (n), sizeof(*(ptr)))
+#define cmpxchg_acq(ptr, o, n) \
+       ia64_cmpxchg(acq, (ptr), (o), (n), sizeof(*(ptr)))
+#define cmpxchg_rel(ptr, o, n) \
+       ia64_cmpxchg(rel, (ptr), (o), (n), sizeof(*(ptr)))
 
 /* for compatibility with other platforms: */
-#define cmpxchg(ptr,o,n)       cmpxchg_acq(ptr,o,n)
+#define cmpxchg(ptr, o, n)     cmpxchg_acq((ptr), (o), (n))
+#define cmpxchg64(ptr, o, n)   cmpxchg_acq((ptr), (o), (n))
+
+#define cmpxchg_local          cmpxchg
+#define cmpxchg64_local                cmpxchg64
 
 #ifdef CONFIG_IA64_DEBUG_CMPXCHG
 # define CMPXCHG_BUGCHECK_DECL int _cmpxchg_bugcheck_count = 128;
index d6345464a2b3bc9b26ec755561fe0358acdf72ae..8a8aa3fd7cd4493dfa6060418bed502cf1bd5227 100644 (file)
@@ -7,8 +7,6 @@
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-# ifdef __KERNEL__
-
 #include <asm/intrinsics.h>
 #include <asm/types.h>
 
@@ -227,5 +225,4 @@ get_order (unsigned long size)
                                         (((current->personality & READ_IMPLIES_EXEC) != 0)     \
                                          ? VM_EXEC : 0))
 
-# endif /* __KERNEL__ */
 #endif /* _ASM_IA64_PAGE_H */
index 78e5a20140aa52f04ec63396c77157402a477954..8b982111034892e3ead84caff7e4ed90ce810b26 100644 (file)
@@ -44,7 +44,7 @@ struct user {
        unsigned long   start_data;             /* data starting address */
        unsigned long   start_stack;            /* stack starting address */
        long int        signal;                 /* signal causing core dump */
-       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   u_ar0;                  /* help gdb find registers */
        unsigned long   magic;                  /* identifies a core file */
        char            u_comm[32];             /* user command name */
 };
index 164448d23850ec312843ba722d7962822f05444d..9dd9e999ea69cdd0a20b7c9e15e6b5788b03f6d5 100644 (file)
@@ -12,7 +12,7 @@ extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
 extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
 extern void __delay(unsigned long loops);
 
 #define udelay(n) (__builtin_constant_p(n) ? \
index bbee8b25d175a0a015418120530928a899ebb23b..67bcd77494a5697942ae2363f19478bdc7fd2197 100644 (file)
@@ -129,8 +129,6 @@ typedef elf_fpreg_t elf_fpregset_t;
    intent than poking at uname or /proc/cpuinfo.  */
 #define ELF_PLATFORM   (NULL)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX)
-#endif
 
 #endif  /* _ASM_M32R__ELF_H */
index def29d095740fa679cd3eb4ad176cb8930844b50..22256d138630508405caf42e7b2986bd7cdec241 100644 (file)
@@ -1,6 +1,366 @@
 #ifndef __M32R_LOCAL_H
 #define __M32R_LOCAL_H
 
-#include <asm-generic/local.h>
+/*
+ *  linux/include/asm-m32r/local.h
+ *
+ *  M32R version:
+ *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
+ *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *    Copyright (C) 2007  Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ */
+
+#include <linux/percpu.h>
+#include <asm/assembler.h>
+#include <asm/system.h>
+#include <asm/local.h>
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ */
+
+/*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+ * not some alias that contains the same information.
+ */
+typedef struct { volatile int counter; } local_t;
+
+#define LOCAL_INIT(i)  { (i) }
+
+/**
+ * local_read - read local variable
+ * @l: pointer of type local_t
+ *
+ * Atomically reads the value of @l.
+ */
+#define local_read(l)  ((l)->counter)
+
+/**
+ * local_set - set local variable
+ * @l: pointer of type local_t
+ * @i: required value
+ *
+ * Atomically sets the value of @l to @i.
+ */
+#define local_set(l, i)        (((l)->counter) = (i))
+
+/**
+ * local_add_return - add long to local variable and return it
+ * @i: long value to add
+ * @l: pointer of type local_t
+ *
+ * Atomically adds @i to @l and return (@i + @l).
+ */
+static inline long local_add_return(long i, local_t *l)
+{
+       unsigned long flags;
+       long result;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# local_add_return             \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               "ld %0, @%1;                    \n\t"
+               "add    %0, %2;                 \n\t"
+               "st %0, @%1;                    \n\t"
+               : "=&r" (result)
+               : "r" (&l->counter), "r" (i)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       return result;
+}
+
+/**
+ * local_sub_return - subtract long from local variable and return it
+ * @i: long value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically subtracts @i from @l and return (@l - @i).
+ */
+static inline long local_sub_return(long i, local_t *l)
+{
+       unsigned long flags;
+       long result;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# local_sub_return             \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               "ld %0, @%1;                    \n\t"
+               "sub    %0, %2;                 \n\t"
+               "st %0, @%1;                    \n\t"
+               : "=&r" (result)
+               : "r" (&l->counter), "r" (i)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       return result;
+}
+
+/**
+ * local_add - add long to local variable
+ * @i: long value to add
+ * @l: pointer of type local_t
+ *
+ * Atomically adds @i to @l.
+ */
+#define local_add(i, l) ((void) local_add_return((i), (l)))
+
+/**
+ * local_sub - subtract the local variable
+ * @i: long value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically subtracts @i from @l.
+ */
+#define local_sub(i, l) ((void) local_sub_return((i), (l)))
+
+/**
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
+
+/**
+ * local_inc_return - increment local variable and return it
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1 and returns the result.
+ */
+static inline long local_inc_return(local_t *l)
+{
+       unsigned long flags;
+       long result;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# local_inc_return             \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               "ld %0, @%1;                    \n\t"
+               "addi   %0, #1;                 \n\t"
+               "st %0, @%1;                    \n\t"
+               : "=&r" (result)
+               : "r" (&l->counter)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       return result;
+}
+
+/**
+ * local_dec_return - decrement local variable and return it
+ * @l: pointer of type local_t
+ *
+ * Atomically decrements @l by 1 and returns the result.
+ */
+static inline long local_dec_return(local_t *l)
+{
+       unsigned long flags;
+       long result;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# local_dec_return             \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               "ld %0, @%1;                    \n\t"
+               "addi   %0, #-1;                \n\t"
+               "st %0, @%1;                    \n\t"
+               : "=&r" (result)
+               : "r" (&l->counter)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       return result;
+}
+
+/**
+ * local_inc - increment local variable
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1.
+ */
+#define local_inc(l) ((void)local_inc_return(l))
+
+/**
+ * local_dec - decrement local variable
+ * @l: pointer of type local_t
+ *
+ * Atomically decrements @l by 1.
+ */
+#define local_dec(l) ((void)local_dec_return(l))
+
+/**
+ * local_inc_and_test - increment and test
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_inc_and_test(l) (local_inc_return(l) == 0)
+
+/**
+ * local_dec_and_test - decrement and test
+ * @l: pointer of type local_t
+ *
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all
+ * other cases.
+ */
+#define local_dec_and_test(l) (local_dec_return(l) == 0)
+
+/**
+ * local_add_negative - add and test if negative
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+#define local_add_negative(i, l) (local_add_return((i), (l)) < 0)
+
+#define local_cmpxchg(l, o, n) (cmpxchg_local(&((l)->counter), (o), (n)))
+#define local_xchg(v, new) (xchg_local(&((l)->counter), new))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+static inline int local_add_unless(local_t *l, long a, long u)
+{
+       long c, old;
+       c = local_read(l);
+       for (;;) {
+               if (unlikely(c == (u)))
+                       break;
+               old = local_cmpxchg((l), c, c + (a));
+               if (likely(old == c))
+                       break;
+               c = old;
+       }
+       return c != (u);
+}
+
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+static inline void local_clear_mask(unsigned long  mask, local_t *addr)
+{
+       unsigned long flags;
+       unsigned long tmp;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# local_clear_mask             \n\t"
+               DCACHE_CLEAR("%0", "r5", "%1")
+               "ld %0, @%1;                    \n\t"
+               "and    %0, %2;                 \n\t"
+               "st %0, @%1;                    \n\t"
+               : "=&r" (tmp)
+               : "r" (addr), "r" (~mask)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r5"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+}
+
+static inline void local_set_mask(unsigned long  mask, local_t *addr)
+{
+       unsigned long flags;
+       unsigned long tmp;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# local_set_mask               \n\t"
+               DCACHE_CLEAR("%0", "r5", "%1")
+               "ld %0, @%1;                    \n\t"
+               "or     %0, %2;                 \n\t"
+               "st %0, @%1;                    \n\t"
+               : "=&r" (tmp)
+               : "r" (addr), "r" (mask)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r5"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+}
+
+/* Atomic operations are already serializing on m32r */
+#define smp_mb__before_local_dec()     barrier()
+#define smp_mb__after_local_dec()      barrier()
+#define smp_mb__before_local_inc()     barrier()
+#define smp_mb__after_local_inc()      barrier()
+
+/* Use these for per-cpu local_t variables: on some archs they are
+ * much more efficient than these naive implementations.  Note they take
+ * a variable, not an address.
+ */
+
+#define __local_inc(l)         ((l)->a.counter++)
+#define __local_dec(l)         ((l)->a.counter++)
+#define __local_add(i, l)      ((l)->a.counter += (i))
+#define __local_sub(i, l)      ((l)->a.counter -= (i))
+
+/* Use these for per-cpu local_t variables: on some archs they are
+ * much more efficient than these naive implementations.  Note they take
+ * a variable, not an address.
+ */
+
+/* Need to disable preemption for the cpu local counters otherwise we could
+   still access a variable of a previous CPU in a non local way. */
+#define cpu_local_wrap_v(l)            \
+       ({ local_t res__;               \
+          preempt_disable();           \
+          res__ = (l);                 \
+          preempt_enable();            \
+          res__; })
+#define cpu_local_wrap(l)              \
+       ({ preempt_disable();           \
+          l;                           \
+          preempt_enable(); })         \
+
+#define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
+
+#define __cpu_local_inc(l)     cpu_local_inc(l)
+#define __cpu_local_dec(l)     cpu_local_dec(l)
+#define __cpu_local_add(i, l)  cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l)  cpu_local_sub((i), (l))
 
 #endif /* __M32R_LOCAL_H */
index 04fd183a2c581d5dd43ab96505b72c283e053d51..05d43bbbf940b022b140edb86256526ea338c620 100644 (file)
@@ -6,7 +6,6 @@
 #define PAGE_SIZE      (1UL << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
-#ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
 extern void clear_page(void *to);
@@ -87,5 +86,4 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_M32R_PAGE_H */
index 2365de5c29553d5d6c3dca5679370c62c6b64c27..70a57c8c002b59e0aa73f9c2c1d443e31f3297b2 100644 (file)
@@ -121,12 +121,13 @@ static inline void local_irq_disable(void)
 
 #define nop()  __asm__ __volatile__ ("nop" : : )
 
-#define xchg(ptr,x) \
-       ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define xchg(ptr, x)                                                   \
+       ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+#define xchg_local(ptr, x)                                             \
+       ((__typeof__(*(ptr)))__xchg_local((unsigned long)(x), (ptr),    \
+                       sizeof(*(ptr))))
 
-#ifdef CONFIG_SMP
 extern void  __xchg_called_with_bad_pointer(void);
-#endif
 
 #ifdef CONFIG_CHIP_M32700_TS1
 #define DCACHE_CLEAR(reg0, reg1, addr)                         \
@@ -146,7 +147,7 @@ extern void  __xchg_called_with_bad_pointer(void);
 #endif /* CONFIG_CHIP_M32700_TS1 */
 
 static __always_inline unsigned long
-__xchg(unsigned long x, volatile void * ptr, int size)
+__xchg(unsigned long x, volatile void *ptr, int size)
 {
        unsigned long flags;
        unsigned long tmp = 0;
@@ -186,9 +187,45 @@ __xchg(unsigned long x, volatile void * ptr, int size)
 #endif /* CONFIG_CHIP_M32700_TS1 */
                );
                break;
+#endif  /* CONFIG_SMP */
+       default:
+               __xchg_called_with_bad_pointer();
+       }
+
+       local_irq_restore(flags);
+
+       return (tmp);
+}
+
+static __always_inline unsigned long
+__xchg_local(unsigned long x, volatile void *ptr, int size)
+{
+       unsigned long flags;
+       unsigned long tmp = 0;
+
+       local_irq_save(flags);
+
+       switch (size) {
+       case 1:
+               __asm__ __volatile__ (
+                       "ldb    %0, @%2 \n\t"
+                       "stb    %1, @%2 \n\t"
+                       : "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+               break;
+       case 2:
+               __asm__ __volatile__ (
+                       "ldh    %0, @%2 \n\t"
+                       "sth    %1, @%2 \n\t"
+                       : "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+               break;
+       case 4:
+               __asm__ __volatile__ (
+                       "ld     %0, @%2 \n\t"
+                       "st     %1, @%2 \n\t"
+                       : "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+               break;
        default:
                __xchg_called_with_bad_pointer();
-#endif  /* CONFIG_SMP */
        }
 
        local_irq_restore(flags);
@@ -228,6 +265,37 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new)
        return retval;
 }
 
+static inline unsigned long
+__cmpxchg_local_u32(volatile unsigned int *p, unsigned int old,
+                       unsigned int new)
+{
+       unsigned long flags;
+       unsigned int retval;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+                       DCACHE_CLEAR("%0", "r4", "%1")
+                       "ld %0, @%1;            \n"
+               "       bne     %0, %2, 1f;     \n"
+                       "st %3, @%1;            \n"
+               "       bra     2f;             \n"
+               "       .fillinsn               \n"
+               "1:"
+                       "st %0, @%1;            \n"
+               "       .fillinsn               \n"
+               "2:"
+                       : "=&r" (retval)
+                       : "r" (p), "r" (old), "r" (new)
+                       : "cbit", "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+                       , "r4"
+#endif  /* CONFIG_CHIP_M32700_TS1 */
+               );
+       local_irq_restore(flags);
+
+       return retval;
+}
+
 /* This function doesn't exist, so you'll get a linker error
    if something tries to do an invalid cmpxchg().  */
 extern void __cmpxchg_called_with_bad_pointer(void);
@@ -247,13 +315,34 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
        return old;
 }
 
-#define cmpxchg(ptr,o,n)                                                \
-  ({                                                                    \
-     __typeof__(*(ptr)) _o_ = (o);                                      \
-     __typeof__(*(ptr)) _n_ = (n);                                      \
-     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,          \
-                                   (unsigned long)_n_, sizeof(*(ptr))); \
-  })
+#define cmpxchg(ptr, o, n)                                              \
+       ((__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)(o),       \
+                       (unsigned long)(n), sizeof(*(ptr))))
+
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+                                     unsigned long old,
+                                     unsigned long new, int size)
+{
+       switch (size) {
+       case 4:
+               return __cmpxchg_local_u32(ptr, old, new);
+       default:
+               return __cmpxchg_local_generic(ptr, old, new, size);
+       }
+
+       return old;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                           \
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),     \
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
 #endif  /* __KERNEL__ */
 
index 035258d713d00f5ebb2508fda4261f956d7855e6..03b3c11c2aff2ba5b2580d96c2c534d65b1f074d 100644 (file)
@@ -38,7 +38,7 @@ struct user {
        unsigned long   start_data;             /* data starting address */
        unsigned long   start_stack;            /* stack starting address */
        long int        signal;                 /* signal causing core dump */
-       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   u_ar0;                  /* help gdb find registers */
        unsigned long   magic;                  /* identifies a core file */
        char            u_comm[32];             /* user command name */
 };
index eb63b85f933674f47e1ea8afab0f7d82d23bd3bd..14ea42152b9785c75925414b7a971212e122604e 100644 (file)
@@ -114,8 +114,6 @@ typedef struct user_m68kfp_struct elf_fpregset_t;
 
 #define ELF_PLATFORM  (NULL)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
-#endif
 
 #endif
index 1431ea0b59e01e5f31c4c075893bf2a4397f55b3..3f29e2a03a43bd203d34c633ed2c5a5749b35b4e 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef _M68K_PAGE_H
 #define _M68K_PAGE_H
 
-
-#ifdef __KERNEL__
-
 #include <linux/const.h>
 
 /* PAGE_SHIFT determines the page size */
@@ -230,6 +227,4 @@ static inline __attribute_const__ int __virt_to_node_shift(void)
 
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _M68K_PAGE_H */
index 778a4c538eb2ed03da163506d93573622bb1a4ab..0b604f0f192d5916b74aee3026c70a7351834671 100644 (file)
@@ -107,8 +107,6 @@ extern void *empty_zero_page;
 /* 64-bit machines, beware!  SRB. */
 #define SIZEOF_PTR_LOG2                               2
 
-#define mm_end_of_chunk(addr, len)     0
-
 extern void kernel_set_cachemode(void *addr, unsigned long size, int cmode);
 
 /*
index caa9b1663e452d509c9c2055335442ff44631edb..dbb6515ffd5b21f3d4a9e1544d7f6544ea604742 100644 (file)
@@ -154,6 +154,10 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
 }
 #endif
 
+#include <asm-generic/cmpxchg-local.h>
+
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
 /*
  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
  * store NEW in MEM.  Return the initial value in MEM.  Success is
@@ -185,9 +189,26 @@ static inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
        return old;
 }
 
-#define cmpxchg(ptr,o,n)\
-       ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
-                                       (unsigned long)(n),sizeof(*(ptr))))
+#define cmpxchg(ptr, o, n)                                                 \
+       ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),           \
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg_local(ptr, o, n)                                           \
+       ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),           \
+                       (unsigned long)(n), sizeof(*(ptr))))
+#else
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
 #endif
 
 #define arch_align_stack(x) (x)
index 8c56ccab4849ca0c86dfba77281d0e52d6ee0b4e..f1f478d6e050d1f11e730c92a9663993e4304337 100644 (file)
@@ -72,8 +72,7 @@ struct user{
                                   esp register.  */
   long int signal;             /* Signal that caused the core dump. */
   int reserved;                        /* No longer used */
-  struct user_regs_struct *u_ar0;
-                               /* Used by gdb to help find the values for */
+  unsigned long u_ar0;         /* Used by gdb to help find the values for */
                                /* the registers. */
   struct user_m68kfp_struct* u_fpstate;        /* Math Co-processor pointer. */
   unsigned long magic;         /* To uniquely identify a core file */
index 40b1ed6827db5d2937feea7469860aa9c9752f6c..27f0ec70fba8d6f54f58677092c5318d7cee8ac0 100644 (file)
@@ -105,8 +105,6 @@ typedef struct user_m68kfp_struct elf_fpregset_t;
 
 #define ELF_PLATFORM  (NULL)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
-#endif
 
 #endif
index 653d9b2d7ddfe5be3799ba95ca715d6898f3c56b..6adef1ee2082c72c4a740d19b091c2c5f19faeb1 100644 (file)
@@ -172,8 +172,6 @@ extern void iounmap(void *addr);
 /*
  * Macros used for converting between virtual and physical mappings.
  */
-#define mm_ptov(vaddr)         ((void *) (vaddr))
-#define mm_vtop(vaddr)         ((unsigned long) (vaddr))
 #define phys_to_virt(vaddr)    ((void *) (vaddr))
 #define virt_to_phys(vaddr)    ((unsigned long) (vaddr))
 
index 9efa0a9851b1ffb26aad17ce1b2a41658731e4ee..6af480c7f2916b5583ba0feb6a1a25afbfebd4ec 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _M68KNOMMU_PAGE_H
 #define _M68KNOMMU_PAGE_H
 
-#ifdef __KERNEL__
-
 /* PAGE_SHIFT determines the page size */
 
 #define PAGE_SHIFT     (12)
@@ -78,6 +76,4 @@ extern unsigned long memory_end;
 
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _M68KNOMMU_PAGE_H */
index ee2dc07bae0e3ef232d8a23b38bcaf3029a1d5d2..039ab3f817328ec639cc2a59ea7a9581463e6623 100644 (file)
@@ -186,26 +186,20 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
 }
 #endif
 
+#include <asm-generic/cmpxchg-local.h>
+
 /*
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
  */
-#define __HAVE_ARCH_CMPXCHG    1
-
-static __inline__ unsigned long
-cmpxchg(volatile int *p, int old, int new)
-{
-       unsigned long flags;
-       int prev;
-
-       local_irq_save(flags);
-       if ((prev = *p) == old)
-               *p = new;
-       local_irq_restore(flags);
-       return(prev);
-}
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
 
 #if defined( CONFIG_M68328 ) || defined( CONFIG_M68EZ328 ) || \
        defined (CONFIG_M68360) || defined( CONFIG_M68VZ328 )
index a5ec0e5dc5b8ec303addaef2fe5fb52f0c9d5670..4a812c3ceb90f3b4781a6ead62d018639a66c0f4 100644 (file)
@@ -104,4 +104,21 @@ extern void __cmpxchg_called_with_bad_pointer(void);
 #define cmpxchg(ptr, old, new)         __cmpxchg(ptr, old, new, smp_llsc_mb())
 #define cmpxchg_local(ptr, old, new)   __cmpxchg(ptr, old, new, )
 
+#define cmpxchg64(ptr, o, n)                                           \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg((ptr), (o), (n));                                       \
+  })
+
+#ifdef CONFIG_64BIT
+#define cmpxchg64_local(ptr, o, n)                                     \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg_local((ptr), (o), (n));                                 \
+  })
+#else
+#include <asm-generic/cmpxchg-local.h>
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#endif
+
 #endif /* __ASM_CMPXCHG_H */
index 766f91ad5cd347c28ae6ef745916465ca67bbf22..f69f7acba6378542b606bed125bd409a3ec90cbf 100644 (file)
@@ -239,8 +239,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
 #endif /* !defined(ELF_ARCH) */
 
-#ifdef __KERNEL__
-
 struct mips_abi;
 
 extern struct mips_abi mips_abi;
@@ -328,8 +326,6 @@ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
 #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs)                  \
        dump_task_fpu(tsk, elf_fpregs)
 
-#endif /* __KERNEL__ */
-
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
index d2ea983bec06f913645a26383b2793feb64d1d64..635aa44d2290dfcb85b056015341ff0580d232b3 100644 (file)
@@ -9,9 +9,6 @@
 #ifndef _ASM_PAGE_H
 #define _ASM_PAGE_H
 
-
-#ifdef __KERNEL__
-
 #include <spaces.h>
 
 /*
@@ -190,6 +187,4 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* defined (__KERNEL__) */
-
 #endif /* _ASM_PAGE_H */
index 61f2a093b91befa8476bbafd52cb291d5588db45..afa83a4c188843bf6b563f7a3a5c2bc70927abd2 100644 (file)
@@ -8,8 +8,6 @@
 #ifndef _ASM_USER_H
 #define _ASM_USER_H
 
-#ifdef __KERNEL__
-
 #include <asm/page.h>
 #include <asm/reg.h>
 
@@ -46,7 +44,7 @@ struct user {
        unsigned long   start_data;             /* data starting address */
        unsigned long   start_stack;            /* stack starting address */
        long int        signal;                 /* signal causing core dump */
-       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   u_ar0;                  /* help gdb find registers */
        unsigned long   magic;                  /* identifies a core file */
        char            u_comm[32];             /* user command name */
 };
@@ -57,6 +55,4 @@ struct user {
 #define HOST_DATA_START_ADDR   (u.start_data)
 #define HOST_STACK_END_ADDR    (u.start_stack + u.u_ssize * NBPG)
 
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_USER_H */
index e894ee35074b05c0890692584ecf4c85bcc2128e..57fcc4a5ebb4e93188fa338f786f49bcf509be35 100644 (file)
@@ -122,6 +122,39 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
                                    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+                                     unsigned long old,
+                                     unsigned long new_, int size)
+{
+       switch (size) {
+#ifdef CONFIG_64BIT
+       case 8: return __cmpxchg_u64((unsigned long *)ptr, old, new_);
+#endif
+       case 4: return __cmpxchg_u32(ptr, old, new_);
+       default:
+               return __cmpxchg_local_generic(ptr, old, new_, size);
+       }
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                       \
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
+                       (unsigned long)(n), sizeof(*(ptr))))
+#ifdef CONFIG_64BIT
+#define cmpxchg64_local(ptr, o, n)                                     \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg_local((ptr), (o), (n));                                 \
+  })
+#else
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#endif
+
 /* Note that we need not lock read accesses - aligned word writes/reads
  * are atomic, so a reader never sees unconsistent values.
  *
index 8e7946a141def9d1dfcd74ad6ffb5a73bd135554..ce0c0d844c7dfe40addc2488e94d2af5c7b2cb72 100644 (file)
@@ -237,14 +237,11 @@ typedef unsigned long elf_greg_t;
 
 #define ELF_PLATFORM  ("PARISC\0" /*+((boot_cpu_data.x86-3)*5) */)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) \
        current->personality = PER_LINUX; \
        current->thread.map_base = DEFAULT_MAP_BASE; \
        current->thread.task_size = DEFAULT_TASK_SIZE \
 
-#endif
-
 /*
  * Fill in general registers in a core dump.  This saves pretty
  * much the same registers as hp-ux, although in a different order.
index b59a1504fc7ae30aaa7722c0427a09d7fd2dd73f..b08d9151c71e4495b1ed9b8884199b92f7c007da 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _PARISC_PAGE_H
 #define _PARISC_PAGE_H
 
-#ifdef __KERNEL__
-
 #include <linux/const.h>
 
 #if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
@@ -175,6 +173,4 @@ extern int npmem_ranges;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _PARISC_PAGE_H */
index 310804485208d49b8f0a5438c33e04186dd2c70d..f42e623030eece0edb4a8f30c37db795c44f2395 100644 (file)
@@ -52,12 +52,26 @@ typedef u64 cputime64_t;
  * Convert cputime <-> jiffies
  */
 extern u64 __cputime_jiffies_factor;
+DECLARE_PER_CPU(unsigned long, cputime_last_delta);
+DECLARE_PER_CPU(unsigned long, cputime_scaled_last_delta);
 
 static inline unsigned long cputime_to_jiffies(const cputime_t ct)
 {
        return mulhdu(ct, __cputime_jiffies_factor);
 }
 
+/* Estimate the scaled cputime by scaling the real cputime based on
+ * the last scaled to real ratio */
+static inline cputime_t cputime_to_scaled(const cputime_t ct)
+{
+       if (cpu_has_feature(CPU_FTR_SPURR) &&
+           per_cpu(cputime_last_delta, smp_processor_id()))
+               return ct *
+                       per_cpu(cputime_scaled_last_delta, smp_processor_id())/
+                       per_cpu(cputime_last_delta, smp_processor_id());
+       return ct;
+}
+
 static inline cputime_t jiffies_to_cputime(const unsigned long jif)
 {
        cputime_t ct;
index 7a4374bdbef48fa482e55682e92e3e8cc74fdfa0..a7e06e25c7083b6648109f66a4e04f551672cf86 100644 (file)
  *
  */
 
-/* see prep_setup_arch() for detailed informations */
-#if defined(CONFIG_SOUND_CS4232) && defined(CONFIG_PPC_PREP)
-extern long ppc_cs4232_dma, ppc_cs4232_dma2;
-#define SND_DMA1 ppc_cs4232_dma
-#define SND_DMA2 ppc_cs4232_dma2
-#else
-#define SND_DMA1 -1
-#define SND_DMA2 -1
-#endif
-
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE   0x00    /* 8 bit slave DMA, channels 0..3 */
 #define IO_DMA2_BASE   0xC0    /* 16 bit master DMA, ch 4(=slave input)..7 */
@@ -269,24 +259,15 @@ static __inline__ void set_dma_page(unsigned int dmanr, int pagenr)
                dma_outb(pagenr >> 8, DMA_HI_PAGE_3);
                break;
        case 5:
-               if (SND_DMA1 == 5 || SND_DMA2 == 5)
-                       dma_outb(pagenr, DMA_LO_PAGE_5);
-               else
-                       dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
+               dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
                dma_outb(pagenr >> 8, DMA_HI_PAGE_5);
                break;
        case 6:
-               if (SND_DMA1 == 6 || SND_DMA2 == 6)
-                       dma_outb(pagenr, DMA_LO_PAGE_6);
-               else
-                       dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+               dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
                dma_outb(pagenr >> 8, DMA_HI_PAGE_6);
                break;
        case 7:
-               if (SND_DMA1 == 7 || SND_DMA2 == 7)
-                       dma_outb(pagenr, DMA_LO_PAGE_7);
-               else
-                       dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
+               dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
                dma_outb(pagenr >> 8, DMA_HI_PAGE_7);
                break;
        }
@@ -302,12 +283,6 @@ static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int phys)
                         ((dmanr & 3) << 1) + IO_DMA1_BASE);
                dma_outb((phys >> 8) & 0xff,
                         ((dmanr & 3) << 1) + IO_DMA1_BASE);
-       } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
-               dma_outb(phys & 0xff,
-                        ((dmanr & 3) << 2) + IO_DMA2_BASE);
-               dma_outb((phys >> 8) & 0xff,
-                        ((dmanr & 3) << 2) + IO_DMA2_BASE);
-               dma_outb((dmanr & 3), DMA2_EXT_REG);
        } else {
                dma_outb((phys >> 1) & 0xff,
                         ((dmanr & 3) << 2) + IO_DMA2_BASE);
@@ -334,11 +309,6 @@ static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
                         ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE);
                dma_outb((count >> 8) & 0xff,
                         ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE);
-       } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
-               dma_outb(count & 0xff,
-                        ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
-               dma_outb((count >> 8) & 0xff,
-                        ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
        } else {
                dma_outb((count >> 1) & 0xff,
                         ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
@@ -368,8 +338,7 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
        count = 1 + dma_inb(io_port);
        count += dma_inb(io_port) << 8;
 
-       return (dmanr <= 3 || dmanr == SND_DMA1 || dmanr == SND_DMA2)
-           ? count : (count << 1);
+       return (dmanr <= 3) ? count : (count << 1);
 }
 
 /* These are in kernel/dma.c: */
index f6dfce025adfe4d117587321782b607028142bbf..748b35ab37b5aa7fdf02291149777d3117803467 100644 (file)
@@ -115,8 +115,6 @@ struct paca_struct {
        u64 system_time;                /* accumulated system TB ticks */
        u64 startpurr;                  /* PURR/TB value snapshot */
        u64 startspurr;                 /* SPURR value snapshot */
-       u64 purrdelta;                  /* FIXME: document */
-       u64 spurrdelta;                 /* FIXME: document */
 };
 
 extern struct paca_struct paca[];
index 236a9210e5fc112b2ba41ab568cc81e4b36ce8e4..61e3725bbd37e18eae791ed2b3cf36e3d045b2eb 100644 (file)
@@ -10,7 +10,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifdef __KERNEL__
 #include <asm/asm-compat.h>
 #include <asm/kdump.h>
 
@@ -194,6 +193,4 @@ struct vm_area_struct;
 #include <asm-generic/memory_model.h>
 #endif /* __ASSEMBLY__ */
 
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_POWERPC_PAGE_H */
index 17110aff26e708c242d9d2fd3855d5d48aea204f..65ea19eec9562b80c06f18bdf518f4ea23e447e1 100644 (file)
@@ -1,6 +1,5 @@
 #ifndef _ASM_POWERPC_PAGE_32_H
 #define _ASM_POWERPC_PAGE_32_H
-#ifdef __KERNEL__
 
 #define VM_DATA_DEFAULT_FLAGS  VM_DATA_DEFAULT_FLAGS32
 
@@ -32,5 +31,4 @@ extern void copy_page(void *to, void *from);
 
 #endif /* __ASSEMBLY__ */
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PAGE_32_H */
index 4ee82c61e4d7ec9ad6b213139f27716d7a19796c..67834eae57028966a943175588b912adb744fe72 100644 (file)
@@ -1,6 +1,5 @@
 #ifndef _ASM_POWERPC_PAGE_64_H
 #define _ASM_POWERPC_PAGE_64_H
-#ifdef __KERNEL__
 
 /*
  * Copyright (C) 2001 PPC64 Team, IBM Corp
@@ -183,5 +182,4 @@ do {                                                \
 
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PAGE_64_H */
index 967930b82ed3591e566ad8755713c507c70511dc..fda98715cd356a4b74a18e66c860c81ed62ee50a 100644 (file)
 #define PS3AV_MONITOR_TYPE_HDMI                        1       /* HDMI */
 #define PS3AV_MONITOR_TYPE_DVI                 2       /* DVI */
 
-#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_60      2       /* 480p */
-#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60   1       /* 480i */
-#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_50      7       /* 576p */
-#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50   6       /* 576i */
-
-#define PS3AV_REGION_60                                0x01
-#define PS3AV_REGION_50                                0x02
-#define PS3AV_REGION_RGB                       0x10
-
-#define get_status(buf)                                (((__u32 *)buf)[2])
-#define PS3AV_HDR_SIZE                         4       /* version + size */
 
 /* for video mode */
+enum ps3av_mode_num {
+       PS3AV_MODE_AUTO                         = 0,
+       PS3AV_MODE_480I                         = 1,
+       PS3AV_MODE_480P                         = 2,
+       PS3AV_MODE_720P60                       = 3,
+       PS3AV_MODE_1080I60                      = 4,
+       PS3AV_MODE_1080P60                      = 5,
+       PS3AV_MODE_576I                         = 6,
+       PS3AV_MODE_576P                         = 7,
+       PS3AV_MODE_720P50                       = 8,
+       PS3AV_MODE_1080I50                      = 9,
+       PS3AV_MODE_1080P50                      = 10,
+       PS3AV_MODE_WXGA                         = 11,
+       PS3AV_MODE_SXGA                         = 12,
+       PS3AV_MODE_WUXGA                        = 13,
+};
+
 #define PS3AV_MODE_MASK                                0x000F
 #define PS3AV_MODE_HDCP_OFF                    0x1000  /* Retail PS3 product doesn't support this */
 #define PS3AV_MODE_DITHER                      0x0800
 #define PS3AV_MODE_RGB                         0x0020
 
 
+#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_60      PS3AV_MODE_480P
+#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60   PS3AV_MODE_480I
+#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_50      PS3AV_MODE_576P
+#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50   PS3AV_MODE_576I
+
+#define PS3AV_REGION_60                                0x01
+#define PS3AV_REGION_50                                0x02
+#define PS3AV_REGION_RGB                       0x10
+
+#define get_status(buf)                                (((__u32 *)buf)[2])
+#define PS3AV_HDR_SIZE                         4       /* version + size */
+
+
 /** command packet structure **/
 struct ps3av_send_hdr {
        u16 version;
@@ -713,8 +732,6 @@ extern int ps3av_set_video_mode(u32);
 extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32);
 extern int ps3av_get_auto_mode(void);
 extern int ps3av_get_mode(void);
-extern int ps3av_get_scanmode(int);
-extern int ps3av_get_refresh_rate(int);
 extern int ps3av_video_mode2res(u32, u32 *, u32 *);
 extern int ps3av_video_mute(int);
 extern int ps3av_audio_mute(int);
index 8d37283db032153dfb53ab504c32cd3878e10828..29552ff182aa161204490d48bb26d9ec1e613e2e 100644 (file)
@@ -463,7 +463,7 @@ __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
        return old;
 }
 
-#define cmpxchg(ptr,o,n)                                                \
+#define cmpxchg(ptr, o, n)                                              \
   ({                                                                    \
      __typeof__(*(ptr)) _o_ = (o);                                      \
      __typeof__(*(ptr)) _n_ = (n);                                      \
@@ -472,7 +472,7 @@ __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
   })
 
 
-#define cmpxchg_local(ptr,o,n)                                          \
+#define cmpxchg_local(ptr, o, n)                                        \
   ({                                                                    \
      __typeof__(*(ptr)) _o_ = (o);                                      \
      __typeof__(*(ptr)) _n_ = (n);                                      \
@@ -492,6 +492,20 @@ __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
  */
 #define NET_IP_ALIGN   0
 #define NET_SKB_PAD    L1_CACHE_BYTES
+
+#define cmpxchg64(ptr, o, n)                                           \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg((ptr), (o), (n));                                       \
+  })
+#define cmpxchg64_local(ptr, o, n)                                     \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg_local((ptr), (o), (n));                                 \
+  })
+#else
+#include <asm-generic/cmpxchg-local.h>
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 #endif
 
 #define arch_align_stack(x) (x)
index e59ade4b3dfb1fdf3d1e10a9ea49b8d79fa7db8d..3fd4545dd74e5ed911ad93fde798aa4a00762b48 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _ASM_POWERPC_USER_H
 #define _ASM_POWERPC_USER_H
 
-#ifdef __KERNEL__
-
 #include <asm/ptrace.h>
 #include <asm/page.h>
 
@@ -40,7 +38,7 @@ struct user {
        unsigned long   start_data;             /* data starting address */
        unsigned long   start_stack;            /* stack starting address */
        long int        signal;                 /* signal causing core dump */
-       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   u_ar0;                  /* help gdb find registers */
        unsigned long   magic;                  /* identifies a core file */
        char            u_comm[32];             /* user command name */
 };
@@ -50,6 +48,4 @@ struct user {
 #define HOST_TEXT_START_ADDR   (u.start_code)
 #define HOST_DATA_START_ADDR   (u.start_data)
 #define HOST_STACK_END_ADDR    (u.start_stack + u.u_ssize * NBPG)
-
-#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_USER_H */
index 51df94c73846c6d248c41e5743732efd5b1ae1f0..0593cb889d45306cf6dac6f5b837ccbca081935f 100644 (file)
@@ -209,12 +209,34 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new)
        return prev;
 }
 
+static inline unsigned long
+__cmpxchg_u32_local(volatile unsigned int *p, unsigned int old,
+       unsigned int new)
+{
+       unsigned int prev;
+
+       __asm__ __volatile__ ("\n\
+1:     lwarx   %0,0,%2 \n\
+       cmpw    0,%0,%3 \n\
+       bne     2f \n"
+       PPC405_ERR77(0,%2)
+"      stwcx.  %4,0,%2 \n\
+       bne-    1b\n"
+"2:"
+       : "=&r" (prev), "=m" (*p)
+       : "r" (p), "r" (old), "r" (new), "m" (*p)
+       : "cc", "memory");
+
+       return prev;
+}
+
 /* This function doesn't exist, so you'll get a linker error
    if something tries to do an invalid cmpxchg().  */
 extern void __cmpxchg_called_with_bad_pointer(void);
 
 static __inline__ unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
+       unsigned int size)
 {
        switch (size) {
        case 4:
@@ -228,7 +250,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
        return old;
 }
 
-#define cmpxchg(ptr,o,n)                                                \
+#define cmpxchg(ptr, o, n)                                              \
   ({                                                                    \
      __typeof__(*(ptr)) _o_ = (o);                                      \
      __typeof__(*(ptr)) _n_ = (n);                                      \
@@ -236,6 +258,31 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
                                    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+                                     unsigned long old,
+                                     unsigned long new, int size)
+{
+       switch (size) {
+       case 4:
+               return __cmpxchg_u32_local(ptr, old, new);
+       default:
+               return __cmpxchg_local_generic(ptr, old, new, size);
+       }
+
+       return old;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                       \
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
 #define arch_align_stack(x) (x)
 
 #endif /* __KERNEL__ */
index 4b3ef7cad11583bf580a6539340e85c4f8e2c5d9..133ce054fc8945dbe4d18a7fe8fd031908410c3b 100644 (file)
@@ -54,6 +54,7 @@ __div(unsigned long long n, unsigned int base)
 #define cputime_lt(__a, __b)           ((__a) <  (__b))
 #define cputime_le(__a, __b)           ((__a) <= (__b))
 #define cputime_to_jiffies(__ct)       (__div((__ct), 1000000 / HZ))
+#define cputime_to_scaled(__ct)                (__ct)
 #define jiffies_to_cputime(__hz)       ((cputime_t)(__hz) * (1000000 / HZ))
 
 #define cputime64_zero                 (0ULL)
index 91d06325cc79b059665ef60f3a00184fc28ca205..b73a424d0f97906d9b2fc8e0640f2b7fefe07d40 100644 (file)
 typedef s390_fp_regs elf_fpregset_t;
 typedef s390_regs elf_gregset_t;
 
-#ifdef __KERNEL__
 #include <linux/sched.h>       /* for task_struct */
 #include <asm/system.h>                /* for save_access_regs */
 
@@ -214,6 +213,5 @@ do {                                                        \
        clear_thread_flag(TIF_31BIT);                   \
 } while (0)
 #endif /* __s390x__ */
-#endif
 
 #endif
index 7592af708b4153975ac3cfc4cc8b1acef19c9c8d..f219c6411e0be1145b10676603a69f25385f9ce2 100644 (file)
@@ -10,7 +10,9 @@
 #ifndef _S390_KEXEC_H
 #define _S390_KEXEC_H
 
+#ifdef __KERNEL__
 #include <asm/page.h>
+#endif
 #include <asm/processor.h>
 /*
  * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
index 584d0ee3c7f60de6f2a0534dc39e2df4ddeaf1b4..a55f9d979dfb0a29aa87d8b61c2d1680529bc31c 100644 (file)
@@ -19,7 +19,6 @@
 #define PAGE_DEFAULT_ACC       0
 #define PAGE_DEFAULT_KEY       (PAGE_DEFAULT_ACC << 4)
 
-#ifdef __KERNEL__
 #include <asm/setup.h>
 #ifndef __ASSEMBLY__
 
@@ -172,6 +171,4 @@ static inline int pfn_valid(unsigned long pfn)
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _S390_PAGE_H */
index 44bda786eef7f11bf86ffc012f661e7c4e545c52..15aba30601a396e7ab020bcb1f1d1c8c49ee61ef 100644 (file)
@@ -201,9 +201,9 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 
 #define __HAVE_ARCH_CMPXCHG 1
 
-#define cmpxchg(ptr,o,n)\
-       ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
-                                       (unsigned long)(n),sizeof(*(ptr))))
+#define cmpxchg(ptr, o, n)                                             \
+       ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),       \
+                                       (unsigned long)(n), sizeof(*(ptr))))
 
 extern void __cmpxchg_called_with_bad_pointer(void);
 
@@ -355,6 +355,44 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
 
 #include <linux/irqflags.h>
 
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+                                     unsigned long old,
+                                     unsigned long new, int size)
+{
+       switch (size) {
+       case 1:
+       case 2:
+       case 4:
+#ifdef __s390x__
+       case 8:
+#endif
+               return __cmpxchg(ptr, old, new, size);
+       default:
+               return __cmpxchg_local_generic(ptr, old, new, size);
+       }
+
+       return old;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                       \
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
+                       (unsigned long)(n), sizeof(*(ptr))))
+#ifdef __s390x__
+#define cmpxchg64_local(ptr, o, n)                                     \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg_local((ptr), (o), (n));                                 \
+  })
+#else
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#endif
+
 /*
  * Use to set psw mask except for the first byte which
  * won't be changed by this function.
index 1dc74baf03c4c16027d1811bfd32bf4be00c21b9..1b050e35fdc6f8448dada25aeb1790d16ee71f35 100644 (file)
@@ -63,8 +63,7 @@ struct user {
                                   the top of the stack is always found in the
                                   esp register.  */
   long int signal;                     /* Signal that caused the core dump. */
-  struct user_regs_struct *u_ar0;
-                               /* Used by gdb to help find the values for */
+  unsigned long u_ar0;         /* Used by gdb to help find the values for */
                                /* the registers. */
   unsigned long magic;         /* To uniquely identify a core file */
   char u_comm[32];             /* User command that was responsible */
index 031db84f2aa150255348ae123778fe84776519bf..d5d464041003bb68104895c2e54ca5d32a46f195 100644 (file)
@@ -12,7 +12,7 @@ extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
 extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
 extern void __delay(unsigned long loops);
 
 #ifdef CONFIG_SUPERH32
index 002e64a4f04950b8fd879cb99d07ed7fadf21c1c..e0fe02950f522b067d75bd8cf4f2d5ecbfeaf41c 100644 (file)
@@ -7,8 +7,6 @@
 
 #include <linux/const.h>
 
-#ifdef __KERNEL__
-
 /* PAGE_SHIFT determines the page size */
 #if defined(CONFIG_PAGE_SIZE_4KB)
 # define PAGE_SHIFT    12
@@ -178,5 +176,4 @@ typedef struct { unsigned long pgd; } pgd_t;
 #define ARCH_SLAB_MINALIGN     8
 #endif
 
-#endif /* __KERNEL__ */
 #endif /* __ASM_SH_PAGE_H */
index 1a4f43c7512605bfca2f5fc1c8c714ed585f9010..8fd3cf6c58d4b31925ce72d2966906ba0456fab6 100644 (file)
@@ -52,7 +52,7 @@ struct user {
        unsigned long   start_data;             /* data starting address */
        unsigned long   start_stack;            /* stack starting address */
        long int        signal;                 /* signal causing core dump */
-       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   u_ar0;                  /* help gdb find registers */
        struct user_fpu_struct* u_fpstate;      /* Math Co-processor pointer */
        unsigned long   magic;                  /* identifies a core file */
        char            u_comm[32];             /* user command name */
index 3328950dbfe6de8df7f8ae1dbad525f9636f38bb..5c944b5a804003f5cc2a87b7972e5c22cd18ceb7 100644 (file)
@@ -17,42 +17,6 @@ typedef struct { volatile int counter; } atomic_t;
 
 #ifdef __KERNEL__
 
-/* Emulate cmpxchg() the same way we emulate atomics,
- * by hashing the object address and indexing into an array
- * of spinlocks to get a bit of performance...
- *
- * See arch/sparc/lib/atomic32.c for implementation.
- *
- * Cribbed from <asm-parisc/atomic.h>
- */
-#define __HAVE_ARCH_CMPXCHG    1
-
-/* bug catcher for when unsupported size is used - won't link */
-extern void __cmpxchg_called_with_bad_pointer(void);
-/* we only need to support cmpxchg of a u32 on sparc */
-extern unsigned long __cmpxchg_u32(volatile u32 *m, u32 old, u32 new_);
-
-/* don't worry...optimizer will get rid of most of this */
-static inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
-{
-       switch(size) {
-       case 4:
-               return __cmpxchg_u32((u32 *)ptr, (u32)old, (u32)new_);
-       default:
-               __cmpxchg_called_with_bad_pointer();
-               break;
-       }
-       return old;
-}
-
-#define cmpxchg(ptr,o,n) ({                                            \
-       __typeof__(*(ptr)) _o_ = (o);                                   \
-       __typeof__(*(ptr)) _n_ = (n);                                   \
-       (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,       \
-                       (unsigned long)_n_, sizeof(*(ptr)));            \
-})
-
 #define ATOMIC_INIT(i)  { (i) }
 
 extern int __atomic_add_return(int, atomic_t *);
index aaf6ef40ee2fc12142794a5bd651fc1c91dd3981..668814e1e5392705fe1d224385f42e51de9261dc 100644 (file)
@@ -85,7 +85,6 @@ typedef struct {
        unsigned int    pr_q[64];
 } elf_fpregset_t;
 
-#ifdef __KERNEL__
 #include <asm/mbus.h>
 #include <asm/uaccess.h>
 
@@ -166,6 +165,4 @@ do {        unsigned long *dest = &(__elf_regs[0]);         \
 
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 
-#endif /* __KERNEL__ */
-
 #endif /* !(__ASMSPARC_ELF_H) */
index ff57648eb8f89f84fa773c09f399829482545b77..cbc48c0c4e15324fdafe23640036a5127315eea1 100644 (file)
@@ -8,8 +8,6 @@
 #ifndef _SPARC_PAGE_H
 #define _SPARC_PAGE_H
 
-#ifdef __KERNEL__
-
 #ifdef CONFIG_SUN4
 #define PAGE_SHIFT   13
 #else
@@ -163,6 +161,4 @@ extern unsigned long pfn_base;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _SPARC_PAGE_H */
index 2655d142b22d192c059cf1fc84858d7b8edba0fd..45e47c159a6e55316e74a35cdd2303b8fb0586a0 100644 (file)
@@ -225,6 +225,54 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int
        return x;
 }
 
+/* Emulate cmpxchg() the same way we emulate atomics,
+ * by hashing the object address and indexing into an array
+ * of spinlocks to get a bit of performance...
+ *
+ * See arch/sparc/lib/atomic32.c for implementation.
+ *
+ * Cribbed from <asm-parisc/atomic.h>
+ */
+#define __HAVE_ARCH_CMPXCHG    1
+
+/* bug catcher for when unsupported size is used - won't link */
+extern void __cmpxchg_called_with_bad_pointer(void);
+/* we only need to support cmpxchg of a u32 on sparc */
+extern unsigned long __cmpxchg_u32(volatile u32 *m, u32 old, u32 new_);
+
+/* don't worry...optimizer will get rid of most of this */
+static inline unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
+{
+       switch (size) {
+       case 4:
+               return __cmpxchg_u32((u32 *)ptr, (u32)old, (u32)new_);
+       default:
+               __cmpxchg_called_with_bad_pointer();
+               break;
+       }
+       return old;
+}
+
+#define cmpxchg(ptr, o, n)                                             \
+({                                                                     \
+       __typeof__(*(ptr)) _o_ = (o);                                   \
+       __typeof__(*(ptr)) _n_ = (n);                                   \
+       (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,       \
+                       (unsigned long)_n_, sizeof(*(ptr)));            \
+})
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
 extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
 
 #endif /* __KERNEL__ */
index 0decdf76371640a45b5fcf43cdb39c862da8f93a..2338a027637705052632b6c535170bc05ca5e312 100644 (file)
 #define __NR_epoll_pwait       309
 #define __NR_utimensat         310
 #define __NR_signalfd          311
-#define __NR_timerfd           312
+#define __NR_timerfd_create    312
 #define __NR_eventfd           313
 #define __NR_fallocate         314
+#define __NR_timerfd_settime   315
+#define __NR_timerfd_gettime   316
 
-#define NR_SYSCALLS            315
+#define NR_SYSCALLS            317
 
 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
  * it never had the plain ones and there is no value to adding those
index 8653e86650097b4de2d7635a6231a1e684fd082c..dc7bc63e507ef67ca455827cddfa33abbb91d0b4 100644 (file)
@@ -7,11 +7,9 @@
  */
 
 #include <asm/ptrace.h>
-#ifdef __KERNEL__
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/spitfire.h>
-#endif
 
 /*
  * Sparc section types
@@ -175,7 +173,6 @@ static inline unsigned int sparc64_elf_hwcap(void)
 
 #define ELF_PLATFORM   (NULL)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2)                     \
 do {   unsigned long new_flags = current_thread_info()->flags; \
        new_flags &= _TIF_32BIT;                        \
@@ -194,6 +191,5 @@ do {        unsigned long new_flags = current_thread_info()->flags; \
        else if (current->personality != PER_LINUX32)   \
                set_personality(PER_LINUX);             \
 } while (0)
-#endif
 
 #endif /* !(__ASM_SPARC64_ELF_H) */
index c299b853b5babae9520be2238620319cf490c149..b6ece223562de86719dc403595eca551140be570 100644 (file)
@@ -16,7 +16,7 @@
 /* BIO layer definitions. */
 extern unsigned long kern_base, kern_size;
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
-#define BIO_VMERGE_BOUNDARY    8192
+#define BIO_VMERGE_BOUNDARY    0
 
 static inline u8 _inb(unsigned long addr)
 {
index 7af1077451ffb9d9fd80daf9086109a4ee039482..cdf950e017eeebad8cb7e553953ac8808ec188ec 100644 (file)
@@ -3,8 +3,6 @@
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
 
-#ifdef __KERNEL__
-
 #include <linux/const.h>
 
 #if defined(CONFIG_SPARC64_PAGE_SIZE_8KB)
@@ -143,5 +141,4 @@ typedef unsigned long pgprot_t;
 
 #include <asm-generic/page.h>
 
-#endif /* __KERNEL__ */
 #endif /* _SPARC64_PAGE_H */
index 99a669c190c776a030ddc2be595693982a1c3fe0..1faefa6d3708c789c757b5e2b2e9e32fa4ae43d1 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/irqflags.h>
+#include <asm-generic/cmpxchg-local.h>
 
 /*
  * Sparc (general) CPU types
@@ -315,6 +316,34 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
                                    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+                                     unsigned long old,
+                                     unsigned long new, int size)
+{
+       switch (size) {
+       case 4:
+       case 8: return __cmpxchg(ptr, old, new, size);
+       default:
+               return __cmpxchg_local_generic(ptr, old, new, size);
+       }
+
+       return old;
+}
+
+#define cmpxchg_local(ptr, o, n)                                       \
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n)                                     \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg_local((ptr), (o), (n));                                 \
+  })
+
 #endif /* !(__ASSEMBLY__) */
 
 #define arch_align_stack(x) (x)
index 2a5e4ebaad805bc89b313a17c38937f9273a2198..c622535c45600bd6c9faab97b40255e71685214d 100644 (file)
 typedef unsigned long cycles_t;
 #define get_cycles()   tick_ops->get_tick()
 
-#define ARCH_HAS_READ_CURRENT_TIMER    1
-#define read_current_timer(timer_val_p)        \
-({     *timer_val_p = tick_ops->get_tick();    \
-       0;                                      \
-})
+#define ARCH_HAS_READ_CURRENT_TIMER
 
 #endif
index cb751b4d0f564aab760af0f6faff8faeb34748e1..77559da0ea3fa92aee70ed7059df904c8bd8656f 100644 (file)
 #define __NR_epoll_pwait       309
 #define __NR_utimensat         310
 #define __NR_signalfd          311
-#define __NR_timerfd           312
+#define __NR_timerfd_create    312
 #define __NR_eventfd           313
 #define __NR_fallocate         314
+#define __NR_timerfd_settime   315
+#define __NR_timerfd_gettime   316
 
-#define NR_SYSCALLS            315
+#define NR_SYSCALLS            317
 
 #ifdef __KERNEL__
 /* sysconf options, for SunOS compatibility */
index 7db8edffb1c68536d90ee7dfa998c8ea3d062a9b..28f5b176ff1af96a2ce47a3b73d6c832967b3917 100644 (file)
@@ -94,8 +94,6 @@ typedef struct user_fpu_struct elf_fpregset_t;
        0;                                                                    \
   } while (0)
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
-#endif
 
 #endif /* __V850_ELF_H__ */
index cc364fcbec101aacadd8641c74c5fc9ac7553985..cdad251fba9ff1802d7f311c660f08b0d9fa0d71 100644 (file)
@@ -122,8 +122,6 @@ outsl (unsigned long port, const void *src, unsigned long count)
 #endif
 
 /* Conversion between virtual and physical mappings.  */
-#define mm_ptov(addr)          ((void *)__phys_to_virt (addr))
-#define mm_vtop(addr)          ((unsigned long)__virt_to_phys (addr))
 #define phys_to_virt(addr)     ((void *)__phys_to_virt (addr))
 #define virt_to_phys(addr)     ((unsigned long)__virt_to_phys (addr))
 
index d693ffb1364d2ae954210cea7542469a1f4a46f9..661d8cd0883954cd0f0312586481bb915dee145e 100644 (file)
@@ -14,8 +14,6 @@
 #ifndef __V850_PAGE_H__
 #define __V850_PAGE_H__
 
-#ifdef __KERNEL__
-
 #include <asm/machdep.h>
 
 
@@ -126,6 +124,4 @@ typedef unsigned long pgprot_t;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#endif /* KERNEL */
-
 #endif /* __V850_PAGE_H__ */
index a34ddfafd56195bae8db73dfa08f987de2a73ed2..7daf1fdee1197f8726e0266edba249b4549d46e1 100644 (file)
@@ -103,6 +103,21 @@ static inline unsigned long __xchg (unsigned long with,
        return tmp;
 }
 
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
 #define arch_align_stack(x) (x)
 
 #endif /* __V850_SYSTEM_H__ */
index ccf4cea6dc9c050bbfd3aab3b3a66255fd9e2245..63cdc567d272e27345152b6fbde8c6222a2c884b 100644 (file)
@@ -3,8 +3,6 @@
 
 /* Adapted from <asm-ppc/user.h>.  */
 
-#ifdef __KERNEL__
-
 #include <linux/ptrace.h>
 #include <asm/page.h>
 
@@ -40,7 +38,7 @@ struct user {
        unsigned long   start_data;             /* data starting address */
        unsigned long   start_stack;            /* stack starting address */
        long int        signal;                 /* signal causing core dump */
-       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   u_ar0;                  /* help gdb find registers */
        unsigned long   magic;                  /* identifies a core file */
        char            u_comm[32];             /* user command name */
 };
@@ -51,6 +49,4 @@ struct user {
 #define HOST_DATA_START_ADDR   (u.start_data)
 #define HOST_STACK_END_ADDR    (u.start_stack + u.u_ssize * NBPG)
 
-#endif /* __KERNEL__ */
-
 #endif /* __V850_USER_H__ */
index 3c6f0f80e827cdd96986236ed98880561185ad74..b04a7ff46df17c2261476741b6e704c8d65ccd52 100644 (file)
@@ -22,7 +22,5 @@ unifdef-y += posix_types_64.h
 unifdef-y += ptrace.h
 unifdef-y += unistd_32.h
 unifdef-y += unistd_64.h
-unifdef-y += user_32.h
-unifdef-y += user_64.h
 unifdef-y += vm86.h
 unifdef-y += vsyscall.h
index 5e182062e6ec98ca49e75729cb93a29e3c1622b4..56f5b41e071c49b2c2f2f50a481858411a4a224e 100644 (file)
@@ -124,11 +124,21 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
        return old;
 }
 
-#define cmpxchg(ptr,o,n)\
-       ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
-                                       (unsigned long)(n),sizeof(*(ptr))))
-#define cmpxchg_local(ptr,o,n)\
-       ((__typeof__(*(ptr)))__cmpxchg_local((ptr),(unsigned long)(o),\
-                                       (unsigned long)(n),sizeof(*(ptr))))
+#define cmpxchg(ptr, o, n)                                             \
+       ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),       \
+                                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64(ptr, o, n)                                           \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg((ptr), (o), (n));                                       \
+  })
+#define cmpxchg_local(ptr, o, n)                                       \
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
+                                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n)                                     \
+  ({                                                                   \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg_local((ptr), (o), (n));                                 \
+  })
 
 #endif
index d11d47fc1a0e8dc44177aa86f62ca2e1090d70d5..409a649204aa7308c8936d6cc08d4479222d6885 100644 (file)
@@ -13,7 +13,7 @@ extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
 extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
 extern void __delay(unsigned long loops);
 
 /* 0x10c7 is 2**32 / 1000000 (rounded up) */
index d9c94e7072894e9d1f584c5da1d9d4704313dcaa..fb62f9941e3855414dd9c53ad404f5ad2cd6d020 100644 (file)
@@ -72,7 +72,6 @@ typedef struct user_fxsr_struct elf_fpxregset_t;
 
 #endif
 
-#ifdef __KERNEL__
 #include <asm/vdso.h>
 
 extern unsigned int vdso_enabled;
@@ -321,6 +320,4 @@ extern int syscall32_setup_pages(struct linux_binprm *, int exstack);
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
-#endif /* __KERNEL__ */
-
 #endif
index 5d6f4ce6e6d64b9fe7dce596f67e4b1165147e77..274a59566c45089d606e323262a08773883bb521 100644 (file)
@@ -107,8 +107,8 @@ static inline int pfn_valid(int pfn)
 /*
  * Following are macros that are specific to this numa platform.
  */
-#define reserve_bootmem(addr, size) \
-       reserve_bootmem_node(NODE_DATA(0), (addr), (size))
+#define reserve_bootmem(addr, size, flags) \
+       reserve_bootmem_node(NODE_DATA(0), (addr), (size), (flags))
 #define alloc_bootmem(x) \
        __alloc_bootmem_node(NODE_DATA(0), (x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
 #define alloc_bootmem_low(x) \
index 315314ce4bfb4f4e14499741e838184f825e3cf7..4f6220db22b110bbf1606d75316a36e1b458fa1a 100644 (file)
@@ -42,19 +42,21 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 static inline void pgd_list_add(pgd_t *pgd)
 {
        struct page *page = virt_to_page(pgd);
+       unsigned long flags;
 
-       spin_lock(&pgd_lock);
+       spin_lock_irqsave(&pgd_lock, flags);
        list_add(&page->lru, &pgd_list);
-       spin_unlock(&pgd_lock);
+       spin_unlock_irqrestore(&pgd_lock, flags);
 }
 
 static inline void pgd_list_del(pgd_t *pgd)
 {
        struct page *page = virt_to_page(pgd);
+       unsigned long flags;
 
-       spin_lock(&pgd_lock);
+       spin_lock_irqsave(&pgd_lock, flags);
        list_del(&page->lru);
-       spin_unlock(&pgd_lock);
+       spin_unlock_irqrestore(&pgd_lock, flags);
 }
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
index d501748700d2aa0518e12bf99f076b8db7029888..f72956331c49349623014bffc4c241f01c361eee 100644 (file)
@@ -41,6 +41,8 @@ struct termio {
 
 #ifdef __KERNEL__
 
+#include <asm/uaccess.h>
+
 /*     intr=^C         quit=^\         erase=del       kill=^U
        eof=^D          vtime=\0        vmin=\1         sxtc=\0
        start=^Q        stop=^S         susp=^Z         eol=\0
@@ -58,39 +60,53 @@ struct termio {
        *(unsigned short *) &(termios)->x = __tmp; \
 }
 
-#define user_termio_to_kernel_termios(termios, termio) \
-({ \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
-       copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
-})
+static inline int user_termio_to_kernel_termios(struct ktermios *termios,
+                                               struct termio __user *termio)
+{
+       SET_LOW_TERMIOS_BITS(termios, termio, c_iflag);
+       SET_LOW_TERMIOS_BITS(termios, termio, c_oflag);
+       SET_LOW_TERMIOS_BITS(termios, termio, c_cflag);
+       SET_LOW_TERMIOS_BITS(termios, termio, c_lflag);
+       return copy_from_user(termios->c_cc, termio->c_cc, NCC);
+}
 
 /*
  * Translate a "termios" structure into a "termio". Ugh.
  */
-#define kernel_termios_to_user_termio(termio, termios) \
-({ \
-       put_user((termios)->c_iflag, &(termio)->c_iflag); \
-       put_user((termios)->c_oflag, &(termio)->c_oflag); \
-       put_user((termios)->c_cflag, &(termio)->c_cflag); \
-       put_user((termios)->c_lflag, &(termio)->c_lflag); \
-       put_user((termios)->c_line,  &(termio)->c_line); \
-       copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
-})
-
-#define user_termios_to_kernel_termios(k, u) \
-       copy_from_user(k, u, sizeof(struct termios2))
-
-#define kernel_termios_to_user_termios(u, k) \
-       copy_to_user(u, k, sizeof(struct termios2))
-
-#define user_termios_to_kernel_termios_1(k, u) \
-       copy_from_user(k, u, sizeof(struct termios))
-
-#define kernel_termios_to_user_termios_1(u, k) \
-       copy_to_user(u, k, sizeof(struct termios))
+static inline int kernel_termios_to_user_termio(struct termio __user *termio,
+                                           struct ktermios *termios)
+{
+       put_user((termios)->c_iflag, &(termio)->c_iflag);
+       put_user((termios)->c_oflag, &(termio)->c_oflag);
+       put_user((termios)->c_cflag, &(termio)->c_cflag);
+       put_user((termios)->c_lflag, &(termio)->c_lflag);
+       put_user((termios)->c_line,  &(termio)->c_line);
+       return copy_to_user((termio)->c_cc, (termios)->c_cc, NCC);
+}
+
+static inline int user_termios_to_kernel_termios(struct ktermios *k,
+                                                struct termios2 __user *u)
+{
+       return copy_from_user(k, u, sizeof(struct termios2));
+}
+
+static inline int kernel_termios_to_user_termios(struct termios2 __user *u,
+                                                struct ktermios *k)
+{
+       return copy_to_user(u, k, sizeof(struct termios2));
+}
+
+static inline int user_termios_to_kernel_termios_1(struct ktermios *k,
+                                                  struct termios __user *u)
+{
+       return copy_from_user(k, u, sizeof(struct termios));
+}
+
+static inline int kernel_termios_to_user_termios_1(struct termios __user *u,
+                                                  struct ktermios *k)
+{
+       return copy_to_user(u, k, sizeof(struct termios));
+}
 
 #endif /* __KERNEL__ */
 
index 27cfd6c599bad2ab649806c3aecefc69cb602947..43e5a78500c57905fa8c24f5397f37a86a13fd7a 100644 (file)
@@ -14,7 +14,6 @@
 #endif
 #define CLOCK_TICK_RATE        PIT_TICK_RATE
 
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER    1
+#define ARCH_HAS_READ_CURRENT_TIMER
 
 #endif
index 484715abe74a66657ffb66fa606b973bb730b103..999873b22e7f4fd9e3531d8a19a47d2e716f96b8 100644 (file)
@@ -1,13 +1,5 @@
-#ifdef __KERNEL__
-# ifdef CONFIG_X86_32
-#  include "user_32.h"
-# else
-#  include "user_64.h"
-# endif
+#ifdef CONFIG_X86_32
+# include "user_32.h"
 #else
-# ifdef __i386__
-#  include "user_32.h"
-# else
-#  include "user_64.h"
-# endif
+# include "user_64.h"
 #endif
index ed8b8fc6906c583878346c6b687f5b97692a12f6..6157da6f882c1c2f8f7b48aa05ea97a4c13d4094 100644 (file)
@@ -116,7 +116,7 @@ struct user{
                                   esp register.  */
   long int signal;                     /* Signal that caused the core dump. */
   int reserved;                        /* No longer used */
-  struct user_pt_regs * u_ar0; /* Used by gdb to help find the values for */
+  unsigned long u_ar0;         /* Used by gdb to help find the values for */
                                /* the registers. */
   struct user_i387_struct* u_fpstate;  /* Math Co-processor pointer. */
   unsigned long magic;         /* To uniquely identify a core file */
index a5449d456cc0a7119037ebae4171d64397ecb27f..96361645560971ba818a050201b6ee3a3b9e8362 100644 (file)
@@ -118,7 +118,7 @@ struct user{
   long int signal;             /* Signal that caused the core dump. */
   int reserved;                        /* No longer used */
   int pad1;
-  struct user_pt_regs * u_ar0; /* Used by gdb to help find the values for */
+  unsigned long u_ar0;         /* Used by gdb to help find the values for */
                                /* the registers. */
   struct user_i387_struct* u_fpstate;  /* Math Co-processor pointer. */
   unsigned long magic;         /* To uniquely identify a core file */
index 7083d46766a8e0284883c0e679f60899b2adc8a6..467384542502640e21fb841e95b2b18cafdb55c1 100644 (file)
@@ -257,8 +257,6 @@ extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *);
        _r->areg[12]=0; _r->areg[13]=0;   _r->areg[14]=0; _r->areg[15]=0; \
   } while (0)
 
-#ifdef __KERNEL__
-
 #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
 
 struct task_struct;
@@ -272,5 +270,4 @@ extern void do_save_fpregs (elf_fpregset_t*, struct pt_regs*,
 extern int do_restore_fpregs (elf_fpregset_t*, struct pt_regs*,
                              struct task_struct*);
 
-#endif /* __KERNEL__ */
 #endif /* _XTENSA_ELF_H */
index 55ce2c9749a3bbdbf6e85836c293e3213ce2accc..1adedbf41d019acd775bd1c8b3b61f664d649979 100644 (file)
@@ -11,8 +11,6 @@
 #ifndef _XTENSA_PAGE_H
 #define _XTENSA_PAGE_H
 
-#ifdef __KERNEL__
-
 #include <asm/processor.h>
 #include <asm/types.h>
 #include <asm/cache.h>
@@ -174,5 +172,4 @@ extern void copy_user_page(void*, void*, unsigned long, struct page*);
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#endif /* __KERNEL__ */
 #endif /* _XTENSA_PAGE_H */
index ddc970847ae9e406c3a9da69e04a190c1acc7151..e0cb9116d8abe10249edcad13fdbcec603447bbe 100644 (file)
@@ -156,8 +156,30 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
                                        (unsigned long)_n_, sizeof (*(ptr))); \
        })
 
+#include <asm-generic/cmpxchg-local.h>
 
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+                                     unsigned long old,
+                                     unsigned long new, int size)
+{
+       switch (size) {
+       case 4:
+               return __cmpxchg_u32(ptr, old, new);
+       default:
+               return __cmpxchg_local_generic(ptr, old, new, size);
+       }
 
+       return old;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
 /*
  * xchg_u32
index 93631229fd5c89e70c378f26d30b72c72d112e02..2ebf068ba504f1afa9112716d141d95cac859baf 100644 (file)
@@ -18,7 +18,6 @@ header-y += usb/
 
 header-y += affs_hardblocks.h
 header-y += aio_abi.h
-header-y += a.out.h
 header-y += arcfb.h
 header-y += atmapi.h
 header-y += atmbr2684.h
@@ -60,7 +59,6 @@ header-y += dqblk_v2.h
 header-y += dqblk_xfs.h
 header-y += efs_fs_sb.h
 header-y += elf-fdpic.h
-header-y += elf.h
 header-y += elf-em.h
 header-y += fadvise.h
 header-y += fd.h
@@ -190,6 +188,7 @@ unifdef-y += dccp.h
 unifdef-y += dirent.h
 unifdef-y += dlm.h
 unifdef-y += edd.h
+unifdef-y += elf.h
 unifdef-y += elfcore.h
 unifdef-y += errno.h
 unifdef-y += errqueue.h
@@ -344,7 +343,6 @@ unifdef-y += uinput.h
 unifdef-y += uio.h
 unifdef-y += unistd.h
 unifdef-y += usbdevice_fs.h
-unifdef-y += user.h
 unifdef-y += utsname.h
 unifdef-y += videodev2.h
 unifdef-y += videodev.h
index f913cc3e1b0da141d273522c751e4003cfc7ec18..82cd918f2ab708ca4545cf863e30f2db187777de 100644 (file)
@@ -128,12 +128,20 @@ enum machine_type {
 #endif
 
 #ifdef linux
+#ifdef __KERNEL__
 #include <asm/page.h>
+#else
+#include <unistd.h>
+#endif
 #if defined(__i386__) || defined(__mc68000__)
 #define SEGMENT_SIZE   1024
 #else
 #ifndef SEGMENT_SIZE
+#ifdef __KERNEL__
 #define SEGMENT_SIZE   PAGE_SIZE
+#else
+#define SEGMENT_SIZE   getpagesize()
+#endif
 #endif
 #endif
 #endif
index 22eb9367235aee14f2e2da4863f450d842287e2b..0260c3e79fddc90ec5ab08694fdfc72d9969860f 100644 (file)
@@ -326,11 +326,7 @@ struct ac97_ops
 #define AC97_DEFAULT_POWER_OFF 4 /* Needs warm reset to power up */
 };
 
-extern int ac97_read_proc (char *page_out, char **start, off_t off,
-                          int count, int *eof, void *data);
 extern int ac97_probe_codec(struct ac97_codec *);
-extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate);
-extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate);
 
 extern struct ac97_codec *ac97_alloc_codec(void);
 extern void ac97_release_codec(struct ac97_codec *codec);
@@ -363,7 +359,4 @@ struct ac97_quirk {
        int type;               /* quirk type above */
 };
 
-struct pci_dev;
-extern int ac97_tune_hardware(struct pci_dev *pdev, struct ac97_quirk *quirk, int override);
-
 #endif /* _AC97_CODEC_H_ */
index 302eb727ecb85dc7dec0db126c9a5d5240d8194b..e8cae54e8d88b9116d4813771978f2acecc58bf2 100644 (file)
@@ -173,7 +173,11 @@ typedef struct acct acct_t;
 static inline u32 jiffies_to_AHZ(unsigned long x)
 {
 #if (TICK_NSEC % (NSEC_PER_SEC / AHZ)) == 0
+# if HZ < AHZ
+       return x * (AHZ / HZ);
+# else
        return x / (HZ / AHZ);
+# endif
 #else
         u64 tmp = (u64)x * TICK_NSEC;
         do_div(tmp, (NSEC_PER_SEC / AHZ));
index bdca3f1b3213ffb4871ed3cc028ae5a1f9257220..eb640f0acfacd629ee179c4b10e639d56a04b93a 100644 (file)
@@ -47,7 +47,6 @@ struct dma_chan_ref {
  * address is an implied source, whereas the asynchronous case it must be listed
  * as a source.  The destination address must be the first address in the source
  * array.
- * @ASYNC_TX_ASSUME_COHERENT: skip cache maintenance operations
  * @ASYNC_TX_ACK: immediately ack the descriptor, precludes setting up a
  * dependency chain
  * @ASYNC_TX_DEP_ACK: ack the dependency descriptor.  Useful for chaining.
@@ -55,7 +54,6 @@ struct dma_chan_ref {
 enum async_tx_flags {
        ASYNC_TX_XOR_ZERO_DST    = (1 << 0),
        ASYNC_TX_XOR_DROP_DST    = (1 << 1),
-       ASYNC_TX_ASSUME_COHERENT = (1 << 2),
        ASYNC_TX_ACK             = (1 << 3),
        ASYNC_TX_DEP_ACK         = (1 << 4),
 };
@@ -64,9 +62,15 @@ enum async_tx_flags {
 void async_tx_issue_pending_all(void);
 enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
 void async_tx_run_dependencies(struct dma_async_tx_descriptor *tx);
+#ifdef CONFIG_ARCH_HAS_ASYNC_TX_FIND_CHANNEL
+#include <asm/async_tx.h>
+#else
+#define async_tx_find_channel(dep, type, dst, dst_count, src, src_count, len) \
+        __async_tx_find_channel(dep, type)
 struct dma_chan *
-async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
+__async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
        enum dma_transaction_type tx_type);
+#endif /* CONFIG_ARCH_HAS_ASYNC_TX_FIND_CHANNEL */
 #else
 static inline void async_tx_issue_pending_all(void)
 {
@@ -88,7 +92,8 @@ async_tx_run_dependencies(struct dma_async_tx_descriptor *tx,
 
 static inline struct dma_chan *
 async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
-       enum dma_transaction_type tx_type)
+       enum dma_transaction_type tx_type, struct page **dst, int dst_count,
+       struct page **src, int src_count, size_t len)
 {
        return NULL;
 }
diff --git a/include/linux/ata_platform.h b/include/linux/ata_platform.h
new file mode 100644 (file)
index 0000000..b856a2a
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __LINUX_ATA_PLATFORM_H
+#define __LINUX_ATA_PLATFORM_H
+
+struct pata_platform_info {
+       /*
+        * I/O port shift, for platforms with ports that are
+        * constantly spaced and need larger than the 1-byte
+        * spacing used by ata_std_ports().
+        */
+       unsigned int ioport_shift;
+       /* 
+        * Indicate platform specific irq types and initial
+        * IRQ flags when call request_irq()
+        */
+       unsigned int irq_flags;
+};
+
+extern int __devinit __pata_platform_probe(struct device *dev,
+                                          struct resource *io_res,
+                                          struct resource *ctl_res,
+                                          struct resource *irq_res,
+                                          unsigned int ioport_shift,
+                                          int __pio_mask);
+
+extern int __devexit __pata_platform_remove(struct device *dev);
+
+/*
+ * Marvell SATA private data
+ */
+struct mv_sata_platform_data {
+       int     n_ports; /* number of sata ports */
+};
+
+#endif /* __LINUX_ATA_PLATFORM_H */
index 0365ec9fc0c9248422801fe71b232d1188a12972..4e4e340592fb08b26cb1c3c5cd7c14d7a9ff9bc9 100644 (file)
@@ -60,8 +60,20 @@ extern void *__alloc_bootmem_core(struct bootmem_data *bdata,
                                  unsigned long goal,
                                  unsigned long limit);
 
+/*
+ * flags for reserve_bootmem (also if CONFIG_HAVE_ARCH_BOOTMEM_NODE,
+ * the architecture-specific code should honor this)
+ */
+#define BOOTMEM_DEFAULT                0
+#define BOOTMEM_EXCLUSIVE      (1<<0)
+
 #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE
-extern void reserve_bootmem(unsigned long addr, unsigned long size);
+/*
+ * If flags is 0, then the return value is always 0 (success). If
+ * flags contains BOOTMEM_EXCLUSIVE, then -EBUSY is returned if the
+ * memory already was reserved.
+ */
+extern int reserve_bootmem(unsigned long addr, unsigned long size, int flags);
 #define alloc_bootmem(x) \
        __alloc_bootmem(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
 #define alloc_bootmem_low(x) \
@@ -84,7 +96,8 @@ extern unsigned long init_bootmem_node(pg_data_t *pgdat,
                                       unsigned long endpfn);
 extern void reserve_bootmem_node(pg_data_t *pgdat,
                                 unsigned long physaddr,
-                                unsigned long size);
+                                unsigned long size,
+                                int flags);
 extern void free_bootmem_node(pg_data_t *pgdat,
                              unsigned long addr,
                              unsigned long size);
index 87479328d46ddf88de95b3038f98134f74fc054e..ff9055fc3d2a046a75e78b8c967b5c732ee7eb24 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/nodemask.h>
 #include <linux/rcupdate.h>
 #include <linux/cgroupstats.h>
+#include <linux/prio_heap.h>
 
 #ifdef CONFIG_CGROUPS
 
@@ -207,6 +208,14 @@ struct cftype {
        int (*release) (struct inode *inode, struct file *file);
 };
 
+struct cgroup_scanner {
+       struct cgroup *cg;
+       int (*test_task)(struct task_struct *p, struct cgroup_scanner *scan);
+       void (*process_task)(struct task_struct *p,
+                       struct cgroup_scanner *scan);
+       struct ptr_heap *heap;
+};
+
 /* Add a new file to the given cgroup directory. Should only be
  * called by subsystems from within a populate() method */
 int cgroup_add_file(struct cgroup *cont, struct cgroup_subsys *subsys,
@@ -233,6 +242,7 @@ int cgroup_is_descendant(const struct cgroup *cont);
 struct cgroup_subsys {
        struct cgroup_subsys_state *(*create)(struct cgroup_subsys *ss,
                                                  struct cgroup *cont);
+       void (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cont);
        void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cont);
        int (*can_attach)(struct cgroup_subsys *ss,
                          struct cgroup *cont, struct task_struct *tsk);
@@ -298,11 +308,17 @@ struct cgroup_iter {
  *    returns NULL or until you want to end the iteration
  *
  * 3) call cgroup_iter_end() to destroy the iterator.
+ *
+ * Or, call cgroup_scan_tasks() to iterate through every task in a cpuset.
+ *    - cgroup_scan_tasks() holds the css_set_lock when calling the test_task()
+ *      callback, but not while calling the process_task() callback.
  */
 void cgroup_iter_start(struct cgroup *cont, struct cgroup_iter *it);
 struct task_struct *cgroup_iter_next(struct cgroup *cont,
                                        struct cgroup_iter *it);
 void cgroup_iter_end(struct cgroup *cont, struct cgroup_iter *it);
+int cgroup_scan_tasks(struct cgroup_scanner *scan);
+int cgroup_attach_task(struct cgroup *, struct task_struct *);
 
 #else /* !CONFIG_CGROUPS */
 
index 9ec43186ba80b840a3e2c4104739201990e7d772..228235c5ae536cf9822ead490e2e280fdf3f45b7 100644 (file)
@@ -37,3 +37,8 @@ SUBSYS(cpuacct)
 
 /* */
 
+#ifdef CONFIG_CGROUP_MEM_CONT
+SUBSYS(mem_cgroup)
+#endif
+
+/* */
index ae0a483bef9bd8a004c2058da2e828d2a0d8b7b5..a671dbff7a1fa229ab45851286ade5eed9b8fef1 100644 (file)
@@ -257,16 +257,8 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
 /*
  * epoll (fs/eventpoll.c) compat bits follow ...
  */
-#ifndef CONFIG_HAS_COMPAT_EPOLL_EVENT
 struct epoll_event;
 #define compat_epoll_event     epoll_event
-#else
-asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd,
-                       struct compat_epoll_event __user *event);
-asmlinkage long compat_sys_epoll_wait(int epfd,
-                       struct compat_epoll_event __user *events,
-                       int maxevents, int timeout);
-#endif
 asmlinkage long compat_sys_epoll_pwait(int epfd,
                        struct compat_epoll_event __user *events,
                        int maxevents, int timeout,
index c4e00161a247975aca754484ecb5f232d1ff4f08..b0fd85ab9efb07efc8c39ef6e3857e29caa93dfb 100644 (file)
@@ -79,7 +79,7 @@ struct cpuidle_state_kobj {
 };
 
 struct cpuidle_device {
-       int                     enabled:1;
+       unsigned int            enabled:1;
        unsigned int            cpu;
 
        int                     last_residency;
index 5c84bf8975939d254f62595e9c4cc0795c8d3c96..acbb364674ff1f8516f50747d0d48375f15df49a 100644 (file)
@@ -94,6 +94,15 @@ enum dma_transaction_type {
 /* last transaction type for creation of the capabilities mask */
 #define DMA_TX_TYPE_END (DMA_INTERRUPT + 1)
 
+/**
+ * enum dma_prep_flags - DMA flags to augment operation preparation
+ * @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of
+ *     this transaction
+ */
+enum dma_prep_flags {
+       DMA_PREP_INTERRUPT = (1 << 0),
+};
+
 /**
  * dma_cap_mask_t - capabilities bitmap modeled after cpumask_t.
  * See linux/cpumask.h
@@ -209,8 +218,6 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param);
  *     descriptors
  * @chan: target channel for this operation
  * @tx_submit: set the prepared descriptor(s) to be executed by the engine
- * @tx_set_dest: set a destination address in a hardware descriptor
- * @tx_set_src: set a source address in a hardware descriptor
  * @callback: routine to call after this operation is complete
  * @callback_param: general parameter to pass to the callback routine
  * ---async_tx api specific fields---
@@ -227,10 +234,6 @@ struct dma_async_tx_descriptor {
        struct list_head tx_list;
        struct dma_chan *chan;
        dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
-       void (*tx_set_dest)(dma_addr_t addr,
-               struct dma_async_tx_descriptor *tx, int index);
-       void (*tx_set_src)(dma_addr_t addr,
-               struct dma_async_tx_descriptor *tx, int index);
        dma_async_tx_callback callback;
        void *callback_param;
        struct list_head depend_list;
@@ -279,15 +282,17 @@ struct dma_device {
        void (*device_free_chan_resources)(struct dma_chan *chan);
 
        struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(
-               struct dma_chan *chan, size_t len, int int_en);
+               struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+               size_t len, unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_xor)(
-               struct dma_chan *chan, unsigned int src_cnt, size_t len,
-               int int_en);
+               struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+               unsigned int src_cnt, size_t len, unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_zero_sum)(
-               struct dma_chan *chan, unsigned int src_cnt, size_t len,
-               u32 *result, int int_en);
+               struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt,
+               size_t len, u32 *result, unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_memset)(
-               struct dma_chan *chan, int value, size_t len, int int_en);
+               struct dma_chan *chan, dma_addr_t dest, int value, size_t len,
+               unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
                struct dma_chan *chan);
 
index 31f6e3c427fbdcdb6e4da6bca8c433ddc3717178..d3c65e48a2e7fa7000319aafbe0f11459e988762 100644 (file)
@@ -6,6 +6,7 @@ struct ds1wm_platform_data {
                             * e.g. on h5xxx and h2200 this is 2
                             * (registers aligned to 4-byte boundaries),
                             * while on hx4700 this is 1 */
+       int active_high;
        void (*enable)(struct platform_device *pdev);
        void (*disable)(struct platform_device *pdev);
 };
index dd57fe523e97572490adb3339c854d4d8ca3266d..a695d63a07afb37a9f3964e4625b5cf3119ef47c 100644 (file)
@@ -41,7 +41,7 @@ extern const struct inode_operations efs_dir_inode_operations;
 extern const struct file_operations efs_dir_operations;
 extern const struct address_space_operations efs_symlink_aops;
 
-extern void efs_read_inode(struct inode *);
+extern struct inode *efs_iget(struct super_block *, unsigned long);
 extern efs_block_t efs_map_block(struct inode *, efs_block_t);
 extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
index 30eb6fbd5323851523a0c2d8033424b86f93eedf..bad1b16ec49a73f432ed27a0c97131205f726c29 100644 (file)
@@ -3,7 +3,9 @@
 
 #include <linux/types.h>
 #include <linux/elf-em.h>
+#ifdef __KERNEL__
 #include <asm/elf.h>
+#endif
 
 struct file;
 
index 9631dddae3486b337b628ce6f0a2986db2bc6172..5ca54d77079f1dd14b713d54e5f4566f01da59dd 100644 (file)
@@ -4,7 +4,9 @@
 #include <linux/types.h>
 #include <linux/signal.h>
 #include <linux/time.h>
+#ifdef __KERNEL__
 #include <linux/user.h>
+#endif
 #include <linux/ptrace.h>
 
 struct elf_siginfo
@@ -14,7 +16,9 @@ struct elf_siginfo
        int     si_errno;                       /* errno */
 };
 
+#ifdef __KERNEL__
 #include <asm/elf.h>
+#endif
 
 #ifndef __KERNEL__
 typedef elf_greg_t greg_t;
index 1ab1d44f8d3be7a28c8a1a849c72e1f841424015..ec87f3142bf30940c31911e71e6638d749de8f04 100644 (file)
@@ -34,6 +34,19 @@ static inline long IS_ERR(const void *ptr)
        return IS_ERR_VALUE((unsigned long)ptr);
 }
 
+/**
+ * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type
+ * @ptr: The pointer to cast.
+ *
+ * Explicitly cast an error-valued pointer to another pointer type in such a
+ * way as to make it clear that's what's going on.
+ */
+static inline void *ERR_CAST(const void *ptr)
+{
+       /* cast away the const */
+       return (void *) ptr;
+}
+
 #endif
 
 #endif /* _LINUX_ERR_H */
index 241c01cb92b24e64027c11341475c030a2a825d3..36c5403963778bcb5a1a5b9193267a616728cdde 100644 (file)
@@ -823,7 +823,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
        sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
        int create, int extend_disksize);
 
-extern void ext3_read_inode (struct inode *);
+extern struct inode *ext3_iget(struct super_block *, unsigned long);
 extern int  ext3_write_inode (struct inode *, int);
 extern int  ext3_setattr (struct dentry *, struct iattr *);
 extern void ext3_delete_inode (struct inode *);
index 1852313fc7c73605887a1447ae33d18645c298c1..c4f635a4dd254ff3ce0a79a976dd3a960925bc81 100644 (file)
@@ -1024,7 +1024,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
                                struct buffer_head *bh_result,
                                int create, int extend_disksize);
 
-extern void ext4_read_inode (struct inode *);
+extern struct inode *ext4_iget(struct super_block *, unsigned long);
 extern int  ext4_write_inode (struct inode *, int);
 extern int  ext4_setattr (struct dentry *, struct iattr *);
 extern void ext4_delete_inode (struct inode *);
index 56bd421c12088e1f294ea04db029eb513a0fc587..36b7abefacbe4b743ba128afcdcfee7b5c05a885 100644 (file)
@@ -21,7 +21,7 @@
 
 /* Fixed constants first: */
 #undef NR_OPEN
-#define NR_OPEN (1024*1024)    /* Absolute upper limit on fd num */
+extern int sysctl_nr_open;
 #define INR_OPEN 1024          /* Initial setting for nfile rlimits */
 
 #define BLOCK_SIZE_BITS 10
@@ -977,7 +977,6 @@ extern int send_sigurg(struct fown_struct *fown);
 extern struct list_head super_blocks;
 extern spinlock_t sb_lock;
 
-#define sb_entry(list) list_entry((list), struct super_block, s_list)
 #define S_BIAS (1<<30)
 struct super_block {
        struct list_head        s_list;         /* Keep this first */
@@ -1242,8 +1241,6 @@ struct super_operations {
        struct inode *(*alloc_inode)(struct super_block *sb);
        void (*destroy_inode)(struct inode *);
 
-       void (*read_inode) (struct inode *);
-  
        void (*dirty_inode) (struct inode *);
        int (*write_inode) (struct inode *, int);
        void (*put_inode) (struct inode *);
@@ -1279,8 +1276,10 @@ struct super_operations {
  *
  * Two bits are used for locking and completion notification, I_LOCK and I_SYNC.
  *
- * I_DIRTY_SYNC                Inode itself is dirty.
- * I_DIRTY_DATASYNC    Data-related inode changes pending
+ * I_DIRTY_SYNC                Inode is dirty, but doesn't have to be written on
+ *                     fdatasync().  i_atime is the usual cause.
+ * I_DIRTY_DATASYNC    Inode is dirty and must be written on fdatasync(), f.e.
+ *                     because i_size changed.
  * I_DIRTY_PAGES       Inode has dirty pages.  Inode itself may be clean.
  * I_NEW               get_new_inode() sets i_state to I_LOCK|I_NEW.  Both
  *                     are cleared by unlock_new_inode(), called from iget().
@@ -1312,8 +1311,6 @@ struct super_operations {
  *                     purpose reduces latency and prevents some filesystem-
  *                     specific deadlocks.
  *
- * Q: Why does I_DIRTY_DATASYNC exist?  It appears as if it could be replaced
- *    by (I_DIRTY_SYNC|I_DIRTY_PAGES).
  * Q: What is the difference between I_WILL_FREE and I_FREEING?
  * Q: igrab() only checks on (I_FREEING|I_WILL_FREE).  Should it also check on
  *    I_CLEAR?  If not, why?
@@ -1768,19 +1765,8 @@ extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*te
 extern struct inode * iget_locked(struct super_block *, unsigned long);
 extern void unlock_new_inode(struct inode *);
 
-static inline struct inode *iget(struct super_block *sb, unsigned long ino)
-{
-       struct inode *inode = iget_locked(sb, ino);
-       
-       if (inode && (inode->i_state & I_NEW)) {
-               sb->s_op->read_inode(inode);
-               unlock_new_inode(inode);
-       }
-
-       return inode;
-}
-
 extern void __iget(struct inode * inode);
+extern void iget_failed(struct inode *);
 extern void clear_inode(struct inode *);
 extern void destroy_inode(struct inode *);
 extern struct inode *new_inode(struct super_block *);
@@ -1942,7 +1928,9 @@ extern int vfs_stat_fd(int dfd, char __user *, struct kstat *);
 extern int vfs_lstat_fd(int dfd, char __user *, struct kstat *);
 extern int vfs_fstat(unsigned int, struct kstat *);
 
-extern int vfs_ioctl(struct file *, unsigned int, unsigned int, unsigned long);
+extern long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
+                   unsigned long arg);
 
 extern void get_filesystem(struct file_system_type *fs);
 extern void put_filesystem(struct file_system_type *fs);
@@ -2113,6 +2101,7 @@ struct ctl_table;
 int proc_nr_files(struct ctl_table *table, int write, struct file *filp,
                  void __user *buffer, size_t *lenp, loff_t *ppos);
 
+int get_filesystem_list(char * buf);
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_FS_H */
index 2bd31fa623b6a7b12c3aa8ac9369cc698b0746d2..d4b7c4ac72e6dd70e9bbda61158b36847e83bb2a 100644 (file)
@@ -91,6 +91,14 @@ static inline void fsnotify_inoderemove(struct inode *inode)
        inotify_inode_is_dead(inode);
 }
 
+/*
+ * fsnotify_link_count - inode's link count changed
+ */
+static inline void fsnotify_link_count(struct inode *inode)
+{
+       inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
+}
+
 /*
  * fsnotify_create - 'name' was linked in
  */
@@ -102,6 +110,20 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
        audit_inode_child(dentry->d_name.name, dentry, inode);
 }
 
+/*
+ * fsnotify_link - new hardlink in 'inode' directory
+ * Note: We have to pass also the linked inode ptr as some filesystems leave
+ *   new_dentry->d_inode NULL and instantiate inode pointer later
+ */
+static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
+{
+       inode_dir_notify(dir, DN_CREATE);
+       inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name,
+                                 inode);
+       fsnotify_link_count(inode);
+       audit_inode_child(new_dentry->d_name.name, new_dentry, dir);
+}
+
 /*
  * fsnotify_mkdir - directory 'name' was created
  */
index acf17bb8e7f963b1ea5400a17d24819f319a8062..06d25c189cc5679d0933747efa4a00b9758a4dca 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef _LINUX_HASH_H
 #define _LINUX_HASH_H
-/* Fast hashing routine for a long.
+/* Fast hashing routine for ints,  longs and pointers.
    (C) 2002 William Lee Irwin III, IBM */
 
 /*
  * them can use shifts and additions instead of multiplications for
  * machines where multiplications are slow.
  */
-#if BITS_PER_LONG == 32
+
+#include <asm/types.h>
+
 /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e370001UL
-#elif BITS_PER_LONG == 64
+#define GOLDEN_RATIO_PRIME_32 0x9e370001UL
 /*  2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL
+#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL
+
+#if BITS_PER_LONG == 32
+#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32
+#define hash_long(val, bits) hash_32(val, bits)
+#elif BITS_PER_LONG == 64
+#define hash_long(val, bits) hash_64(val, bits)
+#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64
 #else
-#error Define GOLDEN_RATIO_PRIME for your wordsize.
+#error Wordsize not 32 or 64
 #endif
 
-static inline unsigned long hash_long(unsigned long val, unsigned int bits)
+static inline u64 hash_64(u64 val, unsigned int bits)
 {
-       unsigned long hash = val;
+       u64 hash = val;
 
-#if BITS_PER_LONG == 64
        /*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
-       unsigned long n = hash;
+       u64 n = hash;
        n <<= 18;
        hash -= n;
        n <<= 33;
@@ -42,15 +49,20 @@ static inline unsigned long hash_long(unsigned long val, unsigned int bits)
        hash += n;
        n <<= 2;
        hash += n;
-#else
+
+       /* High bits are more random, so use them. */
+       return hash >> (64 - bits);
+}
+
+static inline u32 hash_32(u32 val, unsigned int bits)
+{
        /* On some cpus multiply is faster, on others gcc will do shifts */
-       hash *= GOLDEN_RATIO_PRIME;
-#endif
+       u32 hash = val * GOLDEN_RATIO_PRIME_32;
 
        /* High bits are more random, so use them. */
-       return hash >> (BITS_PER_LONG - bits);
+       return hash >> (32 - bits);
 }
-       
+
 static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
 {
        return hash_long((unsigned long)ptr, bits);
index b436be7a7fff35869383b38b3516a83223f69516..2177ee5b2fe21224f3713af0106ebbe1e56125d0 100644 (file)
@@ -71,7 +71,6 @@ struct hayes_esp_config {
 #define ESP_STAT_NEVER_DMA      0x08
 #define ESP_STAT_USE_PIO        0x10
 
-#define ESP_EVENT_WRITE_WAKEUP 0
 #define ESP_MAGIC              0x53ee
 #define ESP_XMIT_SIZE          4096
 
@@ -92,7 +91,6 @@ struct esp_struct {
        unsigned short          closing_wait2;
        int                     IER;    /* Interrupt Enable Register */
        int                     MCR;    /* Modem control register */
-       unsigned long           event;
        unsigned long           last_active;
        int                     line;
        int                     count;      /* # of fd on device */
@@ -101,8 +99,6 @@ struct esp_struct {
        int                     xmit_head;
        int                     xmit_tail;
        int                     xmit_cnt;
-       struct work_struct      tqueue;
-       struct work_struct      tqueue_hangup;
        wait_queue_head_t       open_wait;
        wait_queue_head_t       close_wait;
        wait_queue_head_t       delta_msr_wait;
index db390c511ada863ce1173b267c066b99509a39a5..6115545a5b9cd307819c85c1475e99687097bd84 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/hdlc/ioctl.h>
 
-
-/* Used by all network devices here, pointed to by netdev_priv(dev) */
-struct hdlc_device_desc {
-       int (*netif_rx)(struct sk_buff *skb);
-       struct net_device_stats stats;
-};
-
 /* This structure is a private property of HDLC protocols.
    Hardware drivers have no interest here */
 
@@ -44,12 +37,15 @@ struct hdlc_proto {
        void (*detach)(struct net_device *dev);
        int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
        __be16 (*type_trans)(struct sk_buff *skb, struct net_device *dev);
+       int (*netif_rx)(struct sk_buff *skb);
        struct module *module;
        struct hdlc_proto *next; /* next protocol in the list */
 };
 
 
+/* Pointed to by dev->priv */
 typedef struct hdlc_device {
+       struct net_device_stats stats;
        /* used by HDLC layer to take control over HDLC device from hw driver*/
        int (*attach)(struct net_device *dev,
                      unsigned short encoding, unsigned short parity);
@@ -83,18 +79,11 @@ void unregister_hdlc_protocol(struct hdlc_proto *proto);
 
 struct net_device *alloc_hdlcdev(void *priv);
 
-
-static __inline__ struct hdlc_device_desc* dev_to_desc(struct net_device *dev)
-{
-       return netdev_priv(dev);
-}
-
-static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
+static inline struct hdlc_device* dev_to_hdlc(struct net_device *dev)
 {
-       return netdev_priv(dev) + sizeof(struct hdlc_device_desc);
+       return dev->priv;
 }
 
-
 static __inline__ void debug_frame(const struct sk_buff *skb)
 {
        int i;
@@ -116,13 +105,13 @@ int hdlc_open(struct net_device *dev);
 void hdlc_close(struct net_device *dev);
 
 int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
-                        int (*rx)(struct sk_buff *skb), size_t size);
+                        size_t size);
 /* May be used by hardware driver to gain control over HDLC device */
 void detach_hdlc_protocol(struct net_device *dev);
 
 static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev)
 {
-       return &dev_to_desc(dev)->stats;
+       return &dev_to_hdlc(dev)->stats;
 }
 
 
diff --git a/include/linux/i2c/pca9539.h b/include/linux/i2c/pca9539.h
deleted file mode 100644 (file)
index 611d84a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* platform data for the PCA9539 16-bit I/O expander driver */
-
-struct pca9539_platform_data {
-       /* number of the first GPIO */
-       unsigned        gpio_base;
-
-       /* initial polarity inversion setting */
-       uint16_t        invert;
-
-       void            *context;       /* param to setup/teardown */
-
-       int             (*setup)(struct i2c_client *client,
-                               unsigned gpio, unsigned ngpio,
-                               void *context);
-       int             (*teardown)(struct i2c_client *client,
-                               unsigned gpio, unsigned ngpio,
-                               void *context);
-};
diff --git a/include/linux/i2c/pca953x.h b/include/linux/i2c/pca953x.h
new file mode 100644 (file)
index 0000000..3c73612
--- /dev/null
@@ -0,0 +1,18 @@
+/* platform data for the PCA9539 16-bit I/O expander driver */
+
+struct pca953x_platform_data {
+       /* number of the first GPIO */
+       unsigned        gpio_base;
+
+       /* initial polarity inversion setting */
+       uint16_t        invert;
+
+       void            *context;       /* param to setup/teardown */
+
+       int             (*setup)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+       int             (*teardown)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+};
index 34f40efc7607d1801a0cb5d02407c0db9783a542..79504b22a932fc81df03f75990097bb27b8e5ad7 100644 (file)
@@ -327,7 +327,7 @@ static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, unsigned short t
  * 
  * Returns error if the skb is not of VLAN type
  */
-static inline int __vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
+static inline int __vlan_get_tag(const struct sk_buff *skb, unsigned short *tag)
 {
        struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data;
 
@@ -347,7 +347,8 @@ static inline int __vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
  * 
  * Returns error if @skb->cb[] is not set correctly
  */
-static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *tag)
+static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
+                                        unsigned short *tag)
 {
        struct vlan_skb_tx_cookie *cookie;
 
@@ -370,7 +371,7 @@ static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *ta
  * 
  * Returns error if the skb is not VLAN tagged
  */
-static inline int vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
+static inline int vlan_get_tag(const struct sk_buff *skb, unsigned short *tag)
 {
        if (skb->dev->features & NETIF_F_HW_VLAN_TX) {
                return __vlan_hwaccel_get_tag(skb, tag);
index 90cdbbbbe0778f4d2d26e62d7171cc6e33da335c..a404a0055dd7400489f5cc2ecff32c45d87f61ce 100644 (file)
 #define __FINIT                .previous
 
 #define __INITDATA     .section        ".init.data","aw"
+#define __FINITDATA    .previous
 
 #define __DEVINIT        .section      ".devinit.text", "ax"
 #define __DEVINITDATA    .section      ".devinit.data", "aw"
index c3db4a00f1fab50cbabe3002d8b7041179471ee2..dea7598aeff43c641d72ac18aa506a8fcac9ea57 100644 (file)
@@ -444,4 +444,6 @@ static inline void init_irq_proc(void)
 }
 #endif
 
+int show_interrupts(struct seq_file *p, void *v);
+
 #endif
index d0ecc8eebfbfd8d80b959407d366c6b8650c64c2..9cb2855bb170d34cd4e0b1c6b812312befb3c035 100644 (file)
@@ -507,7 +507,6 @@ typedef struct modem_info {
   struct ktermios      normal_termios;  /* For saving termios structs     */
   struct ktermios      callout_termios;
   wait_queue_head_t    open_wait, close_wait;
-  struct semaphore      write_sem;
   spinlock_t           readlock;
 } modem_info;
 
index 45b3d48f0978d925c42f83be226f85ba58ecfa36..8f4c71759d73fd5ee45b664135650e61572f69c9 100644 (file)
@@ -37,8 +37,6 @@
 #define                BOARD_COUNT     4
 #define                PORT_COUNT      (BOARD_COUNT*16)
 
-#define                SERIAL_TYPE_NORMAL      1
-
 /*   character sizes  */
 
 #define                ISICOM_CS5              0x0000
index 106a5e85e5c434e2fa784bb94c217d5864e6f609..5a84fe944b745ba8c27cd81046abb9e622ac148f 100644 (file)
@@ -71,7 +71,6 @@ struct stliport {
        wait_queue_head_t       open_wait;
        wait_queue_head_t       close_wait;
        wait_queue_head_t       raw_wait;
-       struct work_struct      tqhangup;
        struct asysigs          asig;
        unsigned long           addr;
        unsigned long           rxoffset;
index d9ecd13393b0859ffa98034ec9cb77a3bd8f1912..b18fd3b9b8358c0fe4b6ace4b565176f0163734c 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/lockdep.h>
 
 #include <asm/semaphore.h>
-#endif
 
 #define journal_oom_retry 1
 
@@ -84,7 +83,6 @@ static inline void jbd_free(void *ptr, size_t size)
 
 #define JFS_MIN_JOURNAL_BLOCKS 1024
 
-#ifdef __KERNEL__
 
 /**
  * typedef handle_t - The handle_t type represents a single atomic update being performed by some process.
@@ -924,7 +922,6 @@ extern int     journal_recover    (journal_t *journal);
 extern int        journal_wipe       (journal_t *, int);
 extern int        journal_skip_recovery        (journal_t *);
 extern void       journal_update_superblock    (journal_t *, int);
-extern void       __journal_abort_hard (journal_t *);
 extern void       journal_abort      (journal_t *, int);
 extern int        journal_errno      (journal_t *);
 extern void       journal_ack_err    (journal_t *);
index ff356b2ee478d3dd006e67a76427a467525df7ae..18222f267bc4043f0a0ff0be1201d58938f1063a 100644 (file)
@@ -35,7 +35,7 @@ extern const char linux_proc_banner[];
 #define ALIGN(x,a)             __ALIGN_MASK(x,(typeof(x))(a)-1)
 #define __ALIGN_MASK(x,mask)   (((x)+(mask))&~(mask))
 #define PTR_ALIGN(p, a)                ((typeof(p))ALIGN((unsigned long)(p), (a)))
-#define IS_ALIGNED(x,a)                (((x) % ((typeof(x))(a))) == 0)
+#define IS_ALIGNED(x, a)               (((x) & ((typeof(x))(a) - 1)) == 0)
 
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
 
index 2d9c448d8c52f4c21f61e36890e1219dc074e591..3265968cd2cd4cab38bdff1017e763c24304f842 100644 (file)
@@ -127,17 +127,21 @@ void vmcoreinfo_append_str(const char *fmt, ...)
        __attribute__ ((format (printf, 1, 2)));
 unsigned long paddr_vmcoreinfo_note(void);
 
+#define VMCOREINFO_OSRELEASE(name) \
+       vmcoreinfo_append_str("OSRELEASE=%s\n", #name)
+#define VMCOREINFO_PAGESIZE(value) \
+       vmcoreinfo_append_str("PAGESIZE=%ld\n", value)
 #define VMCOREINFO_SYMBOL(name) \
        vmcoreinfo_append_str("SYMBOL(%s)=%lx\n", #name, (unsigned long)&name)
 #define VMCOREINFO_SIZE(name) \
-       vmcoreinfo_append_str("SIZE(%s)=%lu\n", #name, \
-                             (unsigned long)sizeof(struct name))
-#define VMCOREINFO_TYPEDEF_SIZE(name) \
        vmcoreinfo_append_str("SIZE(%s)=%lu\n", #name, \
                              (unsigned long)sizeof(name))
+#define VMCOREINFO_STRUCT_SIZE(name) \
+       vmcoreinfo_append_str("SIZE(%s)=%lu\n", #name, \
+                             (unsigned long)sizeof(struct name))
 #define VMCOREINFO_OFFSET(name, field) \
        vmcoreinfo_append_str("OFFSET(%s.%s)=%lu\n", #name, #field, \
-                             (unsigned long)&(((struct name *)0)->field))
+                             (unsigned long)offsetof(struct name, field))
 #define VMCOREINFO_LENGTH(name, value) \
        vmcoreinfo_append_str("LENGTH(%s)=%lu\n", #name, (unsigned long)value)
 #define VMCOREINFO_NUMBER(name) \
index 6168c0a441724f198f1999e0f35ce88012750d59..4a6ce82ba03971f832a8f325eb150907090213bc 100644 (file)
@@ -152,8 +152,10 @@ static inline int arch_trampoline_kprobe(struct kprobe *p)
 struct kretprobe {
        struct kprobe kp;
        kretprobe_handler_t handler;
+       kretprobe_handler_t entry_handler;
        int maxactive;
        int nmissed;
+       size_t data_size;
        struct hlist_head free_instances;
        struct hlist_head used_instances;
 };
@@ -164,6 +166,7 @@ struct kretprobe_instance {
        struct kretprobe *rp;
        kprobe_opcode_t *ret_addr;
        struct task_struct *task;
+       char data[0];
 };
 
 struct kretprobe_blackpoint {
index 4374c427778081d0a4e13fbfd3449dd488a7c0ed..bc5a8d0c70902803fe63d4d6b3104e75bfa9c34e 100644 (file)
@@ -457,7 +457,6 @@ struct ata_queued_cmd {
        unsigned long           flags;          /* ATA_QCFLAG_xxx */
        unsigned int            tag;
        unsigned int            n_elem;
-       unsigned int            n_iter;
        unsigned int            mapped_n_elem;
 
        int                     dma_dir;
@@ -1367,7 +1366,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
        qc->nbytes = qc->raw_nbytes = qc->curbytes = 0;
        qc->n_elem = 0;
        qc->mapped_n_elem = 0;
-       qc->n_iter = 0;
        qc->err_mask = 0;
        qc->pad_len = 0;
        qc->last_sg = NULL;
index c8cf5e8ef1717d40cde2768fd0608f29924b1545..25b808631cd92c50d10cf6a31b2d9b9942b62ac9 100644 (file)
@@ -190,4 +190,20 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
        __rounddown_pow_of_two(n)               \
  )
 
+/**
+ * order_base_2 - calculate the (rounded up) base 2 order of the argument
+ * @n: parameter
+ *
+ * The first few values calculated by this routine:
+ *  ob2(0) = 0
+ *  ob2(1) = 0
+ *  ob2(2) = 1
+ *  ob2(3) = 2
+ *  ob2(4) = 2
+ *  ob2(5) = 3
+ *  ... and so on.
+ */
+
+#define order_base_2(n) ilog2(roundup_pow_of_two(n))
+
 #endif /* _LINUX_LOG2_H */
index 26a0a103898f15bd755a7df696e3b9c52ec717cb..46169a7b559b9ebacd3e53c777a692008e4cb37f 100644 (file)
@@ -76,6 +76,7 @@ struct loop_device {
 enum {
        LO_FLAGS_READ_ONLY      = 1,
        LO_FLAGS_USE_AOPS       = 2,
+       LO_FLAGS_AUTOCLEAR      = 4,
 };
 
 #include <asm/posix_types.h>   /* for __kernel_old_dev_t */
index 7059b6b9878a196d0619ab8f200285767752a897..0df024bfd6f0c672a755b2f701711040691f95ae 100644 (file)
@@ -99,7 +99,7 @@
 #ifdef __KERNEL__
 
 #include <linux/wait.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 /* Magic numbers for defining port-device mappings */
 #define LP_PARPORT_UNSPEC -4
@@ -145,7 +145,7 @@ struct lp_struct {
 #endif
        wait_queue_head_t waitq;
        unsigned int last_error;
-       struct semaphore port_mutex;
+       struct mutex port_mutex;
        wait_queue_head_t dataq;
        long timeout;
        unsigned int best_mode;
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
new file mode 100644 (file)
index 0000000..9815951
--- /dev/null
@@ -0,0 +1,190 @@
+/* memcontrol.h - Memory Controller
+ *
+ * Copyright IBM Corporation, 2007
+ * Author Balbir Singh <balbir@linux.vnet.ibm.com>
+ *
+ * Copyright 2007 OpenVZ SWsoft Inc
+ * Author: Pavel Emelianov <xemul@openvz.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.
+ */
+
+#ifndef _LINUX_MEMCONTROL_H
+#define _LINUX_MEMCONTROL_H
+
+#include <linux/rcupdate.h>
+#include <linux/mm.h>
+
+struct mem_cgroup;
+struct page_cgroup;
+struct page;
+struct mm_struct;
+
+#ifdef CONFIG_CGROUP_MEM_CONT
+
+extern void mm_init_cgroup(struct mm_struct *mm, struct task_struct *p);
+extern void mm_free_cgroup(struct mm_struct *mm);
+extern void page_assign_page_cgroup(struct page *page,
+                                       struct page_cgroup *pc);
+extern struct page_cgroup *page_get_page_cgroup(struct page *page);
+extern int mem_cgroup_charge(struct page *page, struct mm_struct *mm,
+                               gfp_t gfp_mask);
+extern void mem_cgroup_uncharge(struct page_cgroup *pc);
+extern void mem_cgroup_uncharge_page(struct page *page);
+extern void mem_cgroup_move_lists(struct page_cgroup *pc, bool active);
+extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
+                                       struct list_head *dst,
+                                       unsigned long *scanned, int order,
+                                       int mode, struct zone *z,
+                                       struct mem_cgroup *mem_cont,
+                                       int active);
+extern void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask);
+extern int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
+                                       gfp_t gfp_mask);
+int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem);
+
+static inline struct mem_cgroup *mm_cgroup(const struct mm_struct *mm)
+{
+       return rcu_dereference(mm->mem_cgroup);
+}
+
+extern int mem_cgroup_prepare_migration(struct page *page);
+extern void mem_cgroup_end_migration(struct page *page);
+extern void mem_cgroup_page_migration(struct page *page, struct page *newpage);
+
+/*
+ * For memory reclaim.
+ */
+extern int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem);
+extern long mem_cgroup_reclaim_imbalance(struct mem_cgroup *mem);
+
+extern int mem_cgroup_get_reclaim_priority(struct mem_cgroup *mem);
+extern void mem_cgroup_note_reclaim_priority(struct mem_cgroup *mem,
+                                                       int priority);
+extern void mem_cgroup_record_reclaim_priority(struct mem_cgroup *mem,
+                                                       int priority);
+
+extern long mem_cgroup_calc_reclaim_active(struct mem_cgroup *mem,
+                               struct zone *zone, int priority);
+extern long mem_cgroup_calc_reclaim_inactive(struct mem_cgroup *mem,
+                               struct zone *zone, int priority);
+
+#else /* CONFIG_CGROUP_MEM_CONT */
+static inline void mm_init_cgroup(struct mm_struct *mm,
+                                       struct task_struct *p)
+{
+}
+
+static inline void mm_free_cgroup(struct mm_struct *mm)
+{
+}
+
+static inline void page_assign_page_cgroup(struct page *page,
+                                               struct page_cgroup *pc)
+{
+}
+
+static inline struct page_cgroup *page_get_page_cgroup(struct page *page)
+{
+       return NULL;
+}
+
+static inline int mem_cgroup_charge(struct page *page, struct mm_struct *mm,
+                                       gfp_t gfp_mask)
+{
+       return 0;
+}
+
+static inline void mem_cgroup_uncharge(struct page_cgroup *pc)
+{
+}
+
+static inline void mem_cgroup_uncharge_page(struct page *page)
+{
+}
+
+static inline void mem_cgroup_move_lists(struct page_cgroup *pc,
+                                               bool active)
+{
+}
+
+static inline int mem_cgroup_cache_charge(struct page *page,
+                                               struct mm_struct *mm,
+                                               gfp_t gfp_mask)
+{
+       return 0;
+}
+
+static inline struct mem_cgroup *mm_cgroup(const struct mm_struct *mm)
+{
+       return NULL;
+}
+
+static inline int task_in_mem_cgroup(struct task_struct *task,
+                                    const struct mem_cgroup *mem)
+{
+       return 1;
+}
+
+static inline int mem_cgroup_prepare_migration(struct page *page)
+{
+       return 0;
+}
+
+static inline void mem_cgroup_end_migration(struct page *page)
+{
+}
+
+static inline void
+mem_cgroup_page_migration(struct page *page, struct page *newpage)
+{
+}
+
+static inline int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem)
+{
+       return 0;
+}
+
+static inline int mem_cgroup_reclaim_imbalance(struct mem_cgroup *mem)
+{
+       return 0;
+}
+
+static inline int mem_cgroup_get_reclaim_priority(struct mem_cgroup *mem)
+{
+       return 0;
+}
+
+static inline void mem_cgroup_note_reclaim_priority(struct mem_cgroup *mem,
+                                               int priority)
+{
+}
+
+static inline void mem_cgroup_record_reclaim_priority(struct mem_cgroup *mem,
+                                               int priority)
+{
+}
+
+static inline long mem_cgroup_calc_reclaim_active(struct mem_cgroup *mem,
+                                       struct zone *zone, int priority)
+{
+       return 0;
+}
+
+static inline long mem_cgroup_calc_reclaim_inactive(struct mem_cgroup *mem,
+                                       struct zone *zone, int priority)
+{
+       return 0;
+}
+#endif /* CONFIG_CGROUP_MEM_CONT */
+
+#endif /* _LINUX_MEMCONTROL_H */
+
diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
new file mode 100644 (file)
index 0000000..4ab2162
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * include/linux/mfd/asic3.h
+ *
+ * Compaq ASIC3 headers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ * Copyright 2007 OpendHand.
+ */
+
+#ifndef __ASIC3_H__
+#define __ASIC3_H__
+
+#include <linux/types.h>
+
+struct asic3 {
+       void __iomem *mapping;
+       unsigned int bus_shift;
+       unsigned int irq_nr;
+       unsigned int irq_base;
+       spinlock_t lock;
+       u16 irq_bothedge[4];
+       struct device *dev;
+};
+
+struct asic3_platform_data {
+       struct {
+               u32 dir;
+               u32 init;
+               u32 sleep_mask;
+               u32 sleep_out;
+               u32 batt_fault_out;
+               u32 sleep_conf;
+               u32 alt_function;
+       } gpio_a, gpio_b, gpio_c, gpio_d;
+
+       unsigned int bus_shift;
+
+       unsigned int irq_base;
+
+       struct platform_device **children;
+       unsigned int n_children;
+};
+
+int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio);
+void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val);
+
+#define ASIC3_NUM_GPIO_BANKS   4
+#define ASIC3_GPIOS_PER_BANK   16
+#define ASIC3_NUM_GPIOS                64
+#define ASIC3_NR_IRQS          ASIC3_NUM_GPIOS + 6
+
+#define ASIC3_GPIO_BANK_A      0
+#define ASIC3_GPIO_BANK_B      1
+#define ASIC3_GPIO_BANK_C      2
+#define ASIC3_GPIO_BANK_D      3
+
+#define ASIC3_GPIO(bank, gpio) \
+       ((ASIC3_GPIOS_PER_BANK * ASIC3_GPIO_BANK_##bank) + (gpio))
+#define ASIC3_GPIO_bit(gpio) (1 << (gpio & 0xf))
+/* All offsets below are specified with this address bus shift */
+#define ASIC3_DEFAULT_ADDR_SHIFT 2
+
+#define ASIC3_OFFSET(base, reg) (ASIC3_##base##_Base + ASIC3_##base##_##reg)
+#define ASIC3_GPIO_OFFSET(base, reg) \
+       (ASIC3_GPIO_##base##_Base + ASIC3_GPIO_##reg)
+
+#define ASIC3_GPIO_A_Base      0x0000
+#define ASIC3_GPIO_B_Base      0x0100
+#define ASIC3_GPIO_C_Base      0x0200
+#define ASIC3_GPIO_D_Base      0x0300
+
+#define ASIC3_GPIO_Mask          0x00    /* R/W 0:don't mask */
+#define ASIC3_GPIO_Direction     0x04    /* R/W 0:input */
+#define ASIC3_GPIO_Out           0x08    /* R/W 0:output low */
+#define ASIC3_GPIO_TriggerType   0x0c    /* R/W 0:level */
+#define ASIC3_GPIO_EdgeTrigger   0x10    /* R/W 0:falling */
+#define ASIC3_GPIO_LevelTrigger  0x14    /* R/W 0:low level detect */
+#define ASIC3_GPIO_SleepMask     0x18    /* R/W 0:don't mask in sleep mode */
+#define ASIC3_GPIO_SleepOut      0x1c    /* R/W level 0:low in sleep mode */
+#define ASIC3_GPIO_BattFaultOut  0x20    /* R/W level 0:low in batt_fault */
+#define ASIC3_GPIO_IntStatus     0x24    /* R/W 0:none, 1:detect */
+#define ASIC3_GPIO_AltFunction   0x28   /* R/W 1:LED register control */
+#define ASIC3_GPIO_SleepConf     0x2c    /*
+                                         * R/W bit 1: autosleep
+                                         * 0: disable gposlpout in normal mode,
+                                         * enable gposlpout in sleep mode.
+                                         */
+#define ASIC3_GPIO_Status        0x30    /* R   Pin status */
+
+#define ASIC3_SPI_Base               0x0400
+#define ASIC3_SPI_Control               0x0000
+#define ASIC3_SPI_TxData                0x0004
+#define ASIC3_SPI_RxData                0x0008
+#define ASIC3_SPI_Int                   0x000c
+#define ASIC3_SPI_Status                0x0010
+
+#define SPI_CONTROL_SPR(clk)      ((clk) & 0x0f)  /* Clock rate */
+
+#define ASIC3_PWM_0_Base                0x0500
+#define ASIC3_PWM_1_Base                0x0600
+#define ASIC3_PWM_TimeBase              0x0000
+#define ASIC3_PWM_PeriodTime            0x0004
+#define ASIC3_PWM_DutyTime              0x0008
+
+#define PWM_TIMEBASE_VALUE(x)    ((x)&0xf)   /* Low 4 bits sets time base */
+#define PWM_TIMEBASE_ENABLE     (1 << 4)   /* Enable clock */
+
+#define ASIC3_LED_0_Base                0x0700
+#define ASIC3_LED_1_Base                0x0800
+#define ASIC3_LED_2_Base                     0x0900
+#define ASIC3_LED_TimeBase              0x0000    /* R/W  7 bits */
+#define ASIC3_LED_PeriodTime            0x0004    /* R/W 12 bits */
+#define ASIC3_LED_DutyTime              0x0008    /* R/W 12 bits */
+#define ASIC3_LED_AutoStopCount         0x000c    /* R/W 16 bits */
+
+/* LED TimeBase bits - match ASIC2 */
+#define LED_TBS                0x0f /* Low 4 bits sets time base, max = 13 */
+                            /* Note: max = 5 on hx4700 */
+                            /* 0: maximum time base */
+                            /* 1: maximum time base / 2 */
+                            /* n: maximum time base / 2^n */
+
+#define LED_EN         (1 << 4) /* LED ON/OFF 0:off, 1:on */
+#define LED_AUTOSTOP   (1 << 5) /* LED ON/OFF auto stop 0:disable, 1:enable */
+#define LED_ALWAYS     (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */
+
+#define ASIC3_CLOCK_Base               0x0A00
+#define ASIC3_CLOCK_CDEX           0x00
+#define ASIC3_CLOCK_SEL            0x04
+
+#define CLOCK_CDEX_SOURCE       (1 << 0)  /* 2 bits */
+#define CLOCK_CDEX_SOURCE0      (1 << 0)
+#define CLOCK_CDEX_SOURCE1      (1 << 1)
+#define CLOCK_CDEX_SPI          (1 << 2)
+#define CLOCK_CDEX_OWM          (1 << 3)
+#define CLOCK_CDEX_PWM0         (1 << 4)
+#define CLOCK_CDEX_PWM1         (1 << 5)
+#define CLOCK_CDEX_LED0         (1 << 6)
+#define CLOCK_CDEX_LED1         (1 << 7)
+#define CLOCK_CDEX_LED2         (1 << 8)
+
+/* Clocks settings: 1 for 24.576 MHz, 0 for 12.288Mhz */
+#define CLOCK_CDEX_SD_HOST      (1 << 9)   /* R/W: SD host clock source */
+#define CLOCK_CDEX_SD_BUS       (1 << 10)  /* R/W: SD bus clock source ctrl */
+#define CLOCK_CDEX_SMBUS        (1 << 11)
+#define CLOCK_CDEX_CONTROL_CX   (1 << 12)
+
+#define CLOCK_CDEX_EX0          (1 << 13)  /* R/W: 32.768 kHz crystal */
+#define CLOCK_CDEX_EX1          (1 << 14)  /* R/W: 24.576 MHz crystal */
+
+#define CLOCK_SEL_SD_HCLK_SEL   (1 << 0)   /* R/W: SDIO host clock select */
+#define CLOCK_SEL_SD_BCLK_SEL   (1 << 1)   /* R/W: SDIO bus clock select */
+
+/* R/W: INT clock source control (32.768 kHz) */
+#define CLOCK_SEL_CX            (1 << 2)
+
+
+#define ASIC3_INTR_Base                0x0B00
+
+#define ASIC3_INTR_IntMask       0x00  /* Interrupt mask control */
+#define ASIC3_INTR_PIntStat      0x04  /* Peripheral interrupt status */
+#define ASIC3_INTR_IntCPS        0x08  /* Interrupt timer clock pre-scale */
+#define ASIC3_INTR_IntTBS        0x0c  /* Interrupt timer set */
+
+#define ASIC3_INTMASK_GINTMASK    (1 << 0)  /* Global INTs mask 1:enable */
+#define ASIC3_INTMASK_GINTEL      (1 << 1)  /* 1: rising edge, 0: hi level */
+#define ASIC3_INTMASK_MASK0       (1 << 2)
+#define ASIC3_INTMASK_MASK1       (1 << 3)
+#define ASIC3_INTMASK_MASK2       (1 << 4)
+#define ASIC3_INTMASK_MASK3       (1 << 5)
+#define ASIC3_INTMASK_MASK4       (1 << 6)
+#define ASIC3_INTMASK_MASK5       (1 << 7)
+
+#define ASIC3_INTR_PERIPHERAL_A   (1 << 0)
+#define ASIC3_INTR_PERIPHERAL_B   (1 << 1)
+#define ASIC3_INTR_PERIPHERAL_C   (1 << 2)
+#define ASIC3_INTR_PERIPHERAL_D   (1 << 3)
+#define ASIC3_INTR_LED0           (1 << 4)
+#define ASIC3_INTR_LED1           (1 << 5)
+#define ASIC3_INTR_LED2           (1 << 6)
+#define ASIC3_INTR_SPI            (1 << 7)
+#define ASIC3_INTR_SMBUS          (1 << 8)
+#define ASIC3_INTR_OWM            (1 << 9)
+
+#define ASIC3_INTR_CPS(x)         ((x)&0x0f)    /* 4 bits, max 14 */
+#define ASIC3_INTR_CPS_SET        (1 << 4)    /* Time base enable */
+
+
+/* Basic control of the SD ASIC */
+#define ASIC3_SDHWCTRL_Base    0x0E00
+#define ASIC3_SDHWCTRL_SDConf    0x00
+
+#define ASIC3_SDHWCTRL_SUSPEND    (1 << 0)  /* 1=suspend all SD operations */
+#define ASIC3_SDHWCTRL_CLKSEL     (1 << 1)  /* 1=SDICK, 0=HCLK */
+#define ASIC3_SDHWCTRL_PCLR       (1 << 2)  /* All registers of SDIO cleared */
+#define ASIC3_SDHWCTRL_LEVCD      (1 << 3)  /* SD card detection: 0:low */
+
+/* SD card write protection: 0=high */
+#define ASIC3_SDHWCTRL_LEVWP      (1 << 4)
+#define ASIC3_SDHWCTRL_SDLED      (1 << 5)  /* SD card LED signal 0=disable */
+
+/* SD card power supply ctrl 1=enable */
+#define ASIC3_SDHWCTRL_SDPWR      (1 << 6)
+
+#define ASIC3_EXTCF_Base               0x1100
+
+#define ASIC3_EXTCF_Select         0x00
+#define ASIC3_EXTCF_Reset          0x04
+
+#define ASIC3_EXTCF_SMOD0               (1 << 0)  /* slot number of mode 0 */
+#define ASIC3_EXTCF_SMOD1               (1 << 1)  /* slot number of mode 1 */
+#define ASIC3_EXTCF_SMOD2               (1 << 2)  /* slot number of mode 2 */
+#define ASIC3_EXTCF_OWM_EN              (1 << 4)  /* enable onewire module */
+#define ASIC3_EXTCF_OWM_SMB             (1 << 5)  /* OWM bus selection */
+#define ASIC3_EXTCF_OWM_RESET            (1 << 6)  /* ?? used by OWM and CF */
+#define ASIC3_EXTCF_CF0_SLEEP_MODE       (1 << 7)  /* CF0 sleep state */
+#define ASIC3_EXTCF_CF1_SLEEP_MODE       (1 << 8)  /* CF1 sleep state */
+#define ASIC3_EXTCF_CF0_PWAIT_EN         (1 << 10) /* CF0 PWAIT_n control */
+#define ASIC3_EXTCF_CF1_PWAIT_EN         (1 << 11) /* CF1 PWAIT_n control */
+#define ASIC3_EXTCF_CF0_BUF_EN           (1 << 12) /* CF0 buffer control */
+#define ASIC3_EXTCF_CF1_BUF_EN           (1 << 13) /* CF1 buffer control */
+#define ASIC3_EXTCF_SD_MEM_ENABLE        (1 << 14)
+#define ASIC3_EXTCF_CF_SLEEP             (1 << 15) /* CF sleep mode control */
+
+/*********************************************
+ *  The Onewire interface registers
+ *
+ *  OWM_CMD
+ *  OWM_DAT
+ *  OWM_INTR
+ *  OWM_INTEN
+ *  OWM_CLKDIV
+ *
+ *********************************************/
+
+#define ASIC3_OWM_Base         0xC00
+
+#define ASIC3_OWM_CMD         0x00
+#define ASIC3_OWM_DAT         0x04
+#define ASIC3_OWM_INTR        0x08
+#define ASIC3_OWM_INTEN       0x0C
+#define ASIC3_OWM_CLKDIV      0x10
+
+#define ASIC3_OWM_CMD_ONEWR         (1 << 0)
+#define ASIC3_OWM_CMD_SRA           (1 << 1)
+#define ASIC3_OWM_CMD_DQO           (1 << 2)
+#define ASIC3_OWM_CMD_DQI           (1 << 3)
+
+#define ASIC3_OWM_INTR_PD          (1 << 0)
+#define ASIC3_OWM_INTR_PDR         (1 << 1)
+#define ASIC3_OWM_INTR_TBE         (1 << 2)
+#define ASIC3_OWM_INTR_TEMP        (1 << 3)
+#define ASIC3_OWM_INTR_RBF         (1 << 4)
+
+#define ASIC3_OWM_INTEN_EPD        (1 << 0)
+#define ASIC3_OWM_INTEN_IAS        (1 << 1)
+#define ASIC3_OWM_INTEN_ETBE       (1 << 2)
+#define ASIC3_OWM_INTEN_ETMT       (1 << 3)
+#define ASIC3_OWM_INTEN_ERBF       (1 << 4)
+
+#define ASIC3_OWM_CLKDIV_PRE       (3 << 0) /* two bits wide at bit 0 */
+#define ASIC3_OWM_CLKDIV_DIV       (7 << 2) /* 3 bits wide at bit 2 */
+
+
+/*****************************************************************************
+ *  The SD configuration registers are at a completely different location
+ *  in memory.  They are divided into three sets of registers:
+ *
+ *  SD_CONFIG         Core configuration register
+ *  SD_CTRL           Control registers for SD operations
+ *  SDIO_CTRL         Control registers for SDIO operations
+ *
+ *****************************************************************************/
+#define ASIC3_SD_CONFIG_Base            0x0400 /* Assumes 32 bit addressing */
+
+#define ASIC3_SD_CONFIG_Command           0x08   /* R/W: Command */
+
+/* [0:8] SD Control Register Base Address */
+#define ASIC3_SD_CONFIG_Addr0             0x20
+
+/* [9:31] SD Control Register Base Address */
+#define ASIC3_SD_CONFIG_Addr1             0x24
+
+/* R/O: interrupt assigned to pin */
+#define ASIC3_SD_CONFIG_IntPin            0x78
+
+/*
+ * Set to 0x1f to clock SD controller, 0 otherwise.
+ * At 0x82 - Gated Clock Ctrl
+ */
+#define ASIC3_SD_CONFIG_ClkStop           0x80
+
+/* Control clock of SD controller */
+#define ASIC3_SD_CONFIG_ClockMode         0x84
+#define ASIC3_SD_CONFIG_SDHC_PinStatus    0x88   /* R/0: SD pins status */
+#define ASIC3_SD_CONFIG_SDHC_Power1       0x90   /* Power1 - manual pwr ctrl */
+
+/* auto power up after card inserted */
+#define ASIC3_SD_CONFIG_SDHC_Power2       0x92
+
+/* auto power down when card removed */
+#define ASIC3_SD_CONFIG_SDHC_Power3       0x94
+#define ASIC3_SD_CONFIG_SDHC_CardDetect   0x98
+#define ASIC3_SD_CONFIG_SDHC_Slot         0xA0   /* R/O: support slot number */
+#define ASIC3_SD_CONFIG_SDHC_ExtGateClk1  0x1E0  /* Not used */
+#define ASIC3_SD_CONFIG_SDHC_ExtGateClk2  0x1E2  /* Not used*/
+
+/* GPIO Output Reg. , at 0x1EA - GPIO Output Enable Reg. */
+#define ASIC3_SD_CONFIG_SDHC_GPIO_OutAndEnable  0x1E8
+#define ASIC3_SD_CONFIG_SDHC_GPIO_Status  0x1EC  /* GPIO Status Reg. */
+
+/* Bit 1: double buffer/single buffer */
+#define ASIC3_SD_CONFIG_SDHC_ExtGateClk3  0x1F0
+
+/* Memory access enable (set to 1 to access SD Controller) */
+#define SD_CONFIG_COMMAND_MAE                (1<<1)
+
+#define SD_CONFIG_CLK_ENABLE_ALL             0x1f
+
+#define SD_CONFIG_POWER1_PC_33V              0x0200    /* Set for 3.3 volts */
+#define SD_CONFIG_POWER1_PC_OFF              0x0000    /* Turn off power */
+
+ /* two bits - number of cycles for card detection */
+#define SD_CONFIG_CARDDETECTMODE_CLK           ((x) & 0x3)
+
+
+#define ASIC3_SD_CTRL_Base            0x1000
+
+#define ASIC3_SD_CTRL_Cmd                  0x00
+#define ASIC3_SD_CTRL_Arg0                 0x08
+#define ASIC3_SD_CTRL_Arg1                 0x0C
+#define ASIC3_SD_CTRL_StopInternal         0x10
+#define ASIC3_SD_CTRL_TransferSectorCount  0x14
+#define ASIC3_SD_CTRL_Response0            0x18
+#define ASIC3_SD_CTRL_Response1            0x1C
+#define ASIC3_SD_CTRL_Response2            0x20
+#define ASIC3_SD_CTRL_Response3            0x24
+#define ASIC3_SD_CTRL_Response4            0x28
+#define ASIC3_SD_CTRL_Response5            0x2C
+#define ASIC3_SD_CTRL_Response6            0x30
+#define ASIC3_SD_CTRL_Response7            0x34
+#define ASIC3_SD_CTRL_CardStatus           0x38
+#define ASIC3_SD_CTRL_BufferCtrl           0x3C
+#define ASIC3_SD_CTRL_IntMaskCard          0x40
+#define ASIC3_SD_CTRL_IntMaskBuffer        0x44
+#define ASIC3_SD_CTRL_CardClockCtrl        0x48
+#define ASIC3_SD_CTRL_MemCardXferDataLen   0x4C
+#define ASIC3_SD_CTRL_MemCardOptionSetup   0x50
+#define ASIC3_SD_CTRL_ErrorStatus0         0x58
+#define ASIC3_SD_CTRL_ErrorStatus1         0x5C
+#define ASIC3_SD_CTRL_DataPort             0x60
+#define ASIC3_SD_CTRL_TransactionCtrl      0x68
+#define ASIC3_SD_CTRL_SoftwareReset        0x1C0
+
+#define SD_CTRL_SOFTWARE_RESET_CLEAR            (1<<0)
+
+#define SD_CTRL_TRANSACTIONCONTROL_SET          (1<<8)
+
+#define SD_CTRL_CARDCLOCKCONTROL_FOR_SD_CARD    (1<<15)
+#define SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK   (1<<8)
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_512    (1<<7)
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_256    (1<<6)
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_128    (1<<5)
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_64     (1<<4)
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_32     (1<<3)
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_16     (1<<2)
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_8      (1<<1)
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_4      (1<<0)
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_2      (0<<0)
+
+#define MEM_CARD_OPTION_REQUIRED                   0x000e
+#define MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(x)   (((x) & 0x0f) << 4)
+#define MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT      (1<<14)
+#define MEM_CARD_OPTION_DATA_XFR_WIDTH_1           (1<<15)
+#define MEM_CARD_OPTION_DATA_XFR_WIDTH_4           0
+
+#define SD_CTRL_COMMAND_INDEX(x)                   ((x) & 0x3f)
+#define SD_CTRL_COMMAND_TYPE_CMD                   (0 << 6)
+#define SD_CTRL_COMMAND_TYPE_ACMD                  (1 << 6)
+#define SD_CTRL_COMMAND_TYPE_AUTHENTICATION        (2 << 6)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_NORMAL       (0 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1       (4 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1B      (5 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R2       (6 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3       (7 << 8)
+#define SD_CTRL_COMMAND_DATA_PRESENT               (1 << 11)
+#define SD_CTRL_COMMAND_TRANSFER_READ              (1 << 12)
+#define SD_CTRL_COMMAND_TRANSFER_WRITE             (0 << 12)
+#define SD_CTRL_COMMAND_MULTI_BLOCK                (1 << 13)
+#define SD_CTRL_COMMAND_SECURITY_CMD               (1 << 14)
+
+#define SD_CTRL_STOP_INTERNAL_ISSSUE_CMD12         (1 << 0)
+#define SD_CTRL_STOP_INTERNAL_AUTO_ISSUE_CMD12     (1 << 8)
+
+#define SD_CTRL_CARDSTATUS_RESPONSE_END            (1 << 0)
+#define SD_CTRL_CARDSTATUS_RW_END                  (1 << 2)
+#define SD_CTRL_CARDSTATUS_CARD_REMOVED_0          (1 << 3)
+#define SD_CTRL_CARDSTATUS_CARD_INSERTED_0         (1 << 4)
+#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_0  (1 << 5)
+#define SD_CTRL_CARDSTATUS_WRITE_PROTECT           (1 << 7)
+#define SD_CTRL_CARDSTATUS_CARD_REMOVED_3          (1 << 8)
+#define SD_CTRL_CARDSTATUS_CARD_INSERTED_3         (1 << 9)
+#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_3  (1 << 10)
+
+#define SD_CTRL_BUFFERSTATUS_CMD_INDEX_ERROR       (1 << 0)
+#define SD_CTRL_BUFFERSTATUS_CRC_ERROR             (1 << 1)
+#define SD_CTRL_BUFFERSTATUS_STOP_BIT_END_ERROR    (1 << 2)
+#define SD_CTRL_BUFFERSTATUS_DATA_TIMEOUT          (1 << 3)
+#define SD_CTRL_BUFFERSTATUS_BUFFER_OVERFLOW       (1 << 4)
+#define SD_CTRL_BUFFERSTATUS_BUFFER_UNDERFLOW      (1 << 5)
+#define SD_CTRL_BUFFERSTATUS_CMD_TIMEOUT           (1 << 6)
+#define SD_CTRL_BUFFERSTATUS_UNK7                  (1 << 7)
+#define SD_CTRL_BUFFERSTATUS_BUFFER_READ_ENABLE    (1 << 8)
+#define SD_CTRL_BUFFERSTATUS_BUFFER_WRITE_ENABLE   (1 << 9)
+#define SD_CTRL_BUFFERSTATUS_ILLEGAL_FUNCTION      (1 << 13)
+#define SD_CTRL_BUFFERSTATUS_CMD_BUSY              (1 << 14)
+#define SD_CTRL_BUFFERSTATUS_ILLEGAL_ACCESS        (1 << 15)
+
+#define SD_CTRL_INTMASKCARD_RESPONSE_END           (1 << 0)
+#define SD_CTRL_INTMASKCARD_RW_END                 (1 << 2)
+#define SD_CTRL_INTMASKCARD_CARD_REMOVED_0         (1 << 3)
+#define SD_CTRL_INTMASKCARD_CARD_INSERTED_0        (1 << 4)
+#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_0 (1 << 5)
+#define SD_CTRL_INTMASKCARD_UNK6                   (1 << 6)
+#define SD_CTRL_INTMASKCARD_WRITE_PROTECT          (1 << 7)
+#define SD_CTRL_INTMASKCARD_CARD_REMOVED_3         (1 << 8)
+#define SD_CTRL_INTMASKCARD_CARD_INSERTED_3        (1 << 9)
+#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_3 (1 << 10)
+
+#define SD_CTRL_INTMASKBUFFER_CMD_INDEX_ERROR      (1 << 0)
+#define SD_CTRL_INTMASKBUFFER_CRC_ERROR            (1 << 1)
+#define SD_CTRL_INTMASKBUFFER_STOP_BIT_END_ERROR   (1 << 2)
+#define SD_CTRL_INTMASKBUFFER_DATA_TIMEOUT         (1 << 3)
+#define SD_CTRL_INTMASKBUFFER_BUFFER_OVERFLOW      (1 << 4)
+#define SD_CTRL_INTMASKBUFFER_BUFFER_UNDERFLOW     (1 << 5)
+#define SD_CTRL_INTMASKBUFFER_CMD_TIMEOUT          (1 << 6)
+#define SD_CTRL_INTMASKBUFFER_UNK7                 (1 << 7)
+#define SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE   (1 << 8)
+#define SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE  (1 << 9)
+#define SD_CTRL_INTMASKBUFFER_ILLEGAL_FUNCTION     (1 << 13)
+#define SD_CTRL_INTMASKBUFFER_CMD_BUSY             (1 << 14)
+#define SD_CTRL_INTMASKBUFFER_ILLEGAL_ACCESS       (1 << 15)
+
+#define SD_CTRL_DETAIL0_RESPONSE_CMD_ERROR                   (1 << 0)
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_NON_CMD12 (1 << 2)
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_CMD12     (1 << 3)
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_READ_DATA          (1 << 4)
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_WRITE_CRC_STATUS   (1 << 5)
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_NON_CMD12     (1 << 8)
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_CMD12         (1 << 9)
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_READ_DATA              (1 << 10)
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_WRITE_CMD              (1 << 11)
+
+#define SD_CTRL_DETAIL1_NO_CMD_RESPONSE                      (1 << 0)
+#define SD_CTRL_DETAIL1_TIMEOUT_READ_DATA                    (1 << 4)
+#define SD_CTRL_DETAIL1_TIMEOUT_CRS_STATUS                   (1 << 5)
+#define SD_CTRL_DETAIL1_TIMEOUT_CRC_BUSY                     (1 << 6)
+
+#define ASIC3_SDIO_CTRL_Base          0x1200
+
+#define ASIC3_SDIO_CTRL_Cmd                  0x00
+#define ASIC3_SDIO_CTRL_CardPortSel          0x04
+#define ASIC3_SDIO_CTRL_Arg0                 0x08
+#define ASIC3_SDIO_CTRL_Arg1                 0x0C
+#define ASIC3_SDIO_CTRL_TransferBlockCount   0x14
+#define ASIC3_SDIO_CTRL_Response0            0x18
+#define ASIC3_SDIO_CTRL_Response1            0x1C
+#define ASIC3_SDIO_CTRL_Response2            0x20
+#define ASIC3_SDIO_CTRL_Response3            0x24
+#define ASIC3_SDIO_CTRL_Response4            0x28
+#define ASIC3_SDIO_CTRL_Response5            0x2C
+#define ASIC3_SDIO_CTRL_Response6            0x30
+#define ASIC3_SDIO_CTRL_Response7            0x34
+#define ASIC3_SDIO_CTRL_CardStatus           0x38
+#define ASIC3_SDIO_CTRL_BufferCtrl           0x3C
+#define ASIC3_SDIO_CTRL_IntMaskCard          0x40
+#define ASIC3_SDIO_CTRL_IntMaskBuffer        0x44
+#define ASIC3_SDIO_CTRL_CardXferDataLen      0x4C
+#define ASIC3_SDIO_CTRL_CardOptionSetup      0x50
+#define ASIC3_SDIO_CTRL_ErrorStatus0         0x54
+#define ASIC3_SDIO_CTRL_ErrorStatus1         0x58
+#define ASIC3_SDIO_CTRL_DataPort             0x60
+#define ASIC3_SDIO_CTRL_TransactionCtrl      0x68
+#define ASIC3_SDIO_CTRL_CardIntCtrl          0x6C
+#define ASIC3_SDIO_CTRL_ClocknWaitCtrl       0x70
+#define ASIC3_SDIO_CTRL_HostInformation      0x74
+#define ASIC3_SDIO_CTRL_ErrorCtrl            0x78
+#define ASIC3_SDIO_CTRL_LEDCtrl              0x7C
+#define ASIC3_SDIO_CTRL_SoftwareReset        0x1C0
+
+#define ASIC3_MAP_SIZE                      0x2000
+
+#endif /* __ASIC3_H__ */
index f4c03e0b355e04dbbbc05f9500350d632ef87bd6..34023c65d4669bc4c4894d392e9d915db3710034 100644 (file)
@@ -88,6 +88,9 @@ struct page {
        void *virtual;                  /* Kernel virtual address (NULL if
                                           not kmapped, ie. highmem) */
 #endif /* WANT_PAGE_VIRTUAL */
+#ifdef CONFIG_CGROUP_MEM_CONT
+       unsigned long page_cgroup;
+#endif
 };
 
 /*
@@ -219,6 +222,9 @@ struct mm_struct {
        /* aio bits */
        rwlock_t                ioctx_list_lock;
        struct kioctx           *ioctx_list;
+#ifdef CONFIG_CGROUP_MEM_CONT
+       struct mem_cgroup *mem_cgroup;
+#endif
 };
 
 #endif /* _LINUX_MM_TYPES_H */
diff --git a/include/linux/pata_platform.h b/include/linux/pata_platform.h
deleted file mode 100644 (file)
index 6a7a92d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __LINUX_PATA_PLATFORM_H
-#define __LINUX_PATA_PLATFORM_H
-
-struct pata_platform_info {
-       /*
-        * I/O port shift, for platforms with ports that are
-        * constantly spaced and need larger than the 1-byte
-        * spacing used by ata_std_ports().
-        */
-       unsigned int ioport_shift;
-       /* 
-        * Indicate platform specific irq types and initial
-        * IRQ flags when call request_irq()
-        */
-       unsigned int irq_flags;
-};
-
-extern int __devinit __pata_platform_probe(struct device *dev,
-                                          struct resource *io_res,
-                                          struct resource *ctl_res,
-                                          struct resource *irq_res,
-                                          unsigned int ioport_shift,
-                                          int __pio_mask);
-
-extern int __devexit __pata_platform_remove(struct device *dev);
-
-#endif /* __LINUX_PATA_PLATFORM_H */
index 39d32837265bad125cc14ef80bda71e8554ada07..df6dd79a0d3b8cc377c772f2fe1410ef39b873ce 100644 (file)
 #define PCI_DEVICE_ID_QUATECH_DSC100   0x0020
 #define PCI_DEVICE_ID_QUATECH_ESC100D  0x0050
 #define PCI_DEVICE_ID_QUATECH_ESC100M  0x0060
+#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278
 
 #define PCI_VENDOR_ID_SEALEVEL         0x135e
 #define PCI_DEVICE_ID_SEALEVEL_U530    0x7101
index 50faa0ea28e4a7a392f617863e0ab82d4d9c330c..1ac969724bb2fff929c397be1cbdcdf007a61953 100644 (file)
@@ -54,7 +54,7 @@
 #ifdef CONFIG_SMP
 
 struct percpu_data {
-       void *ptrs[NR_CPUS];
+       void *ptrs[1];
 };
 
 #define __percpu_disguise(pdata) (struct percpu_data *)~(unsigned long)(pdata)
index 40fac8c4559d3c081f07cd35f7bb8c3e5dedf09b..28dfc61cf79e590d18c6ba62cbb8ee66b8101d89 100644 (file)
@@ -348,6 +348,7 @@ enum
        FLOW_KEY_RTCLASSID,
        FLOW_KEY_SKUID,
        FLOW_KEY_SKGID,
+       FLOW_KEY_VLAN_TAG,
        __FLOW_KEY_MAX,
 };
 
index b9339d8b95bcbf68c0f0c4d304734748f40472e7..cd6332b88829e1fdf7d1f8e25356993905953ea4 100644 (file)
@@ -258,6 +258,7 @@ extern struct pnp_protocol isapnp_protocol;
 #else
 #define pnp_device_is_isapnp(dev) 0
 #endif
+extern struct mutex pnp_res_mutex;
 
 #ifdef CONFIG_PNPBIOS
 extern struct pnp_protocol pnpbios_protocol;
index 515bff053de8a55900e223019452950d178d81b9..6ab80714a9169c67ae116b5e4b0ae9aaceb4620e 100644 (file)
@@ -204,6 +204,41 @@ static inline void user_enable_block_step(struct task_struct *task)
 }
 #endif /* arch_has_block_step */
 
+#ifndef arch_ptrace_stop_needed
+/**
+ * arch_ptrace_stop_needed - Decide whether arch_ptrace_stop() should be called
+ * @code:      current->exit_code value ptrace will stop with
+ * @info:      siginfo_t pointer (or %NULL) for signal ptrace will stop with
+ *
+ * This is called with the siglock held, to decide whether or not it's
+ * necessary to release the siglock and call arch_ptrace_stop() with the
+ * same @code and @info arguments.  It can be defined to a constant if
+ * arch_ptrace_stop() is never required, or always is.  On machines where
+ * this makes sense, it should be defined to a quick test to optimize out
+ * calling arch_ptrace_stop() when it would be superfluous.  For example,
+ * if the thread has not been back to user mode since the last stop, the
+ * thread state might indicate that nothing needs to be done.
+ */
+#define arch_ptrace_stop_needed(code, info)    (0)
+#endif
+
+#ifndef arch_ptrace_stop
+/**
+ * arch_ptrace_stop - Do machine-specific work before stopping for ptrace
+ * @code:      current->exit_code value ptrace will stop with
+ * @info:      siginfo_t pointer (or %NULL) for signal ptrace will stop with
+ *
+ * This is called with no locks held when arch_ptrace_stop_needed() has
+ * just returned nonzero.  It is allowed to block, e.g. for user memory
+ * access.  The arch can have machine-specific work to be done before
+ * ptrace stops.  On ia64, register backing store gets written back to user
+ * memory here.  Since this can be costly (requires dropping the siglock),
+ * we only do it when the arch requires it for this particular stop, as
+ * indicated by arch_ptrace_stop_needed().
+ */
+#define arch_ptrace_stop(code, info)           do { } while (0)
+#endif
+
 #endif
 
 #endif
index 19bc9b8b6191eb1bd458fecb8e00595f966b14c2..34a196ee794182a01ef26e4a9acba7df444875e7 100644 (file)
@@ -110,6 +110,7 @@ struct qnx4_inode_info {
        struct inode vfs_inode;
 };
 
+extern struct inode *qnx4_iget(struct super_block *, unsigned long);
 extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd);
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
index 306a1d1a5af070fc5823c4d0f6e6a3f3192650c7..e51b531cd0b2d970631bc6097019869b74c55830 100644 (file)
@@ -244,6 +244,8 @@ struct bitmap {
         */
        unsigned long daemon_lastrun; /* jiffies of last run */
        unsigned long daemon_sleep; /* how many seconds between updates? */
+       unsigned long last_end_sync; /* when we lasted called end_sync to
+                                     * update bitmap with resync progress */
 
        atomic_t pending_writes; /* pending writes to the bitmap file */
        wait_queue_head_t write_wait;
@@ -275,6 +277,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset,
 int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int degraded);
 void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted);
 void bitmap_close_sync(struct bitmap *bitmap);
+void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector);
 
 void bitmap_unplug(struct bitmap *bitmap);
 void bitmap_daemon_work(struct bitmap *bitmap);
index dcb729244f47e193cf71a192c920a9f674e2a99f..85a068bab625a85d9a62e34859eed5e580a31b16 100644 (file)
@@ -81,6 +81,8 @@ struct mdk_rdev_s
 #define        In_sync         2               /* device is in_sync with rest of array */
 #define        WriteMostly     4               /* Avoid reading if at all possible */
 #define        BarriersNotsupp 5               /* BIO_RW_BARRIER is not supported */
+#define        AllReserved     6               /* If whole device is reserved for
+                                        * one array */
 
        int desc_nr;                    /* descriptor index in the superblock */
        int raid_disk;                  /* role of device in array */
@@ -130,6 +132,9 @@ struct mddev_s
                                        minor_version,
                                        patch_version;
        int                             persistent;
+       int                             external;       /* metadata is
+                                                        * managed externally */
+       char                            metadata_type[17]; /* externally set*/
        int                             chunk_size;
        time_t                          ctime, utime;
        int                             level, layout;
@@ -216,6 +221,8 @@ struct mddev_s
        atomic_t                        recovery_active; /* blocks scheduled, but not written */
        wait_queue_head_t               recovery_wait;
        sector_t                        recovery_cp;
+       sector_t                        resync_max;     /* resync should pause
+                                                        * when it gets here */
 
        spinlock_t                      write_lock;
        wait_queue_head_t               sb_wait;        /* for waiting on superblock updates */
@@ -306,23 +313,17 @@ static inline char * mdname (mddev_t * mddev)
  * iterates through some rdev ringlist. It's safe to remove the
  * current 'rdev'. Dont touch 'tmp' though.
  */
-#define ITERATE_RDEV_GENERIC(head,rdev,tmp)                            \
+#define rdev_for_each_list(rdev, tmp, list)                            \
                                                                        \
-       for ((tmp) = (head).next;                                       \
+       for ((tmp) = (list).next;                                       \
                (rdev) = (list_entry((tmp), mdk_rdev_t, same_set)),     \
-                       (tmp) = (tmp)->next, (tmp)->prev != &(head)     \
+                       (tmp) = (tmp)->next, (tmp)->prev != &(list)     \
                ; )
 /*
  * iterates through the 'same array disks' ringlist
  */
-#define ITERATE_RDEV(mddev,rdev,tmp)                                   \
-       ITERATE_RDEV_GENERIC((mddev)->disks,rdev,tmp)
-
-/*
- * Iterates through 'pending RAID disks'
- */
-#define ITERATE_RDEV_PENDING(rdev,tmp)                                 \
-       ITERATE_RDEV_GENERIC(pending_raid_disks,rdev,tmp)
+#define rdev_for_each(rdev, tmp, mddev)                                \
+       rdev_for_each_list(rdev, tmp, (mddev)->disks)
 
 typedef struct mdk_thread_s {
        void                    (*run) (mddev_t *mddev);
index d32c14de270ea28a1490c3241fe71057a1b0f582..37a642c54871f24166bec8e9b23b73e3369848bb 100644 (file)
@@ -174,10 +174,13 @@ struct rcu_head {
  * code.
  */
 
-#define rcu_assign_pointer(p, v)       ({ \
-                                               smp_wmb(); \
-                                               (p) = (v); \
-                                       })
+#define rcu_assign_pointer(p, v) \
+       ({ \
+               if (!__builtin_constant_p(v) || \
+                   ((v) != NULL)) \
+                       smp_wmb(); \
+               (p) = (v); \
+       })
 
 /**
  * synchronize_sched - block until all CPUs have exited any non-preemptive
diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
new file mode 100644 (file)
index 0000000..61363ce
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef __RES_COUNTER_H__
+#define __RES_COUNTER_H__
+
+/*
+ * Resource Counters
+ * Contain common data types and routines for resource accounting
+ *
+ * Copyright 2007 OpenVZ SWsoft Inc
+ *
+ * Author: Pavel Emelianov <xemul@openvz.org>
+ *
+ */
+
+#include <linux/cgroup.h>
+
+/*
+ * The core object. the cgroup that wishes to account for some
+ * resource may include this counter into its structures and use
+ * the helpers described beyond
+ */
+
+struct res_counter {
+       /*
+        * the current resource consumption level
+        */
+       unsigned long long usage;
+       /*
+        * the limit that usage cannot exceed
+        */
+       unsigned long long limit;
+       /*
+        * the number of unsuccessful attempts to consume the resource
+        */
+       unsigned long long failcnt;
+       /*
+        * the lock to protect all of the above.
+        * the routines below consider this to be IRQ-safe
+        */
+       spinlock_t lock;
+};
+
+/*
+ * Helpers to interact with userspace
+ * res_counter_read/_write - put/get the specified fields from the
+ * res_counter struct to/from the user
+ *
+ * @counter:     the counter in question
+ * @member:  the field to work with (see RES_xxx below)
+ * @buf:     the buffer to opeate on,...
+ * @nbytes:  its size...
+ * @pos:     and the offset.
+ */
+
+ssize_t res_counter_read(struct res_counter *counter, int member,
+               const char __user *buf, size_t nbytes, loff_t *pos,
+               int (*read_strategy)(unsigned long long val, char *s));
+ssize_t res_counter_write(struct res_counter *counter, int member,
+               const char __user *buf, size_t nbytes, loff_t *pos,
+               int (*write_strategy)(char *buf, unsigned long long *val));
+
+/*
+ * the field descriptors. one for each member of res_counter
+ */
+
+enum {
+       RES_USAGE,
+       RES_LIMIT,
+       RES_FAILCNT,
+};
+
+/*
+ * helpers for accounting
+ */
+
+void res_counter_init(struct res_counter *counter);
+
+/*
+ * charge - try to consume more resource.
+ *
+ * @counter: the counter
+ * @val: the amount of the resource. each controller defines its own
+ *       units, e.g. numbers, bytes, Kbytes, etc
+ *
+ * returns 0 on success and <0 if the counter->usage will exceed the
+ * counter->limit _locked call expects the counter->lock to be taken
+ */
+
+int res_counter_charge_locked(struct res_counter *counter, unsigned long val);
+int res_counter_charge(struct res_counter *counter, unsigned long val);
+
+/*
+ * uncharge - tell that some portion of the resource is released
+ *
+ * @counter: the counter
+ * @val: the amount of the resource
+ *
+ * these calls check for usage underflow and show a warning on the console
+ * _locked call expects the counter->lock to be taken
+ */
+
+void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val);
+void res_counter_uncharge(struct res_counter *counter, unsigned long val);
+
+static inline bool res_counter_limit_check_locked(struct res_counter *cnt)
+{
+       if (cnt->usage < cnt->limit)
+               return true;
+
+       return false;
+}
+
+/*
+ * Helper function to detect if the cgroup is within it's limit or
+ * not. It's currently called from cgroup_rss_prepare()
+ */
+static inline bool res_counter_check_under_limit(struct res_counter *cnt)
+{
+       bool ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cnt->lock, flags);
+       ret = res_counter_limit_check_locked(cnt);
+       spin_unlock_irqrestore(&cnt->lock, flags);
+       return ret;
+}
+
+#endif
index 97347f22fc207ba25892536a4443c5c49bc5c90e..1383692ac5bd8c8dc5c06498a38795a256f56c93 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/spinlock.h>
+#include <linux/memcontrol.h>
 
 /*
  * The anon_vma heads a list of private "related" vmas, to scan if
@@ -86,7 +87,7 @@ static inline void page_dup_rmap(struct page *page, struct vm_area_struct *vma,
 /*
  * Called from mm/vmscan.c to handle paging out
  */
-int page_referenced(struct page *, int is_locked);
+int page_referenced(struct page *, int is_locked, struct mem_cgroup *cnt);
 int try_to_unmap(struct page *, int ignore_refs);
 
 /*
@@ -114,7 +115,7 @@ int page_mkclean(struct page *);
 #define anon_vma_prepare(vma)  (0)
 #define anon_vma_link(vma)     do {} while (0)
 
-#define page_referenced(page,l) TestClearPageReferenced(page)
+#define page_referenced(page,l,cnt) TestClearPageReferenced(page)
 #define try_to_unmap(page, refs) SWAP_FAIL
 
 static inline int page_mkclean(struct page *page)
index 9c13be3a21e80509100ffb8ea8fda59fa238c7cf..8a4812c1c038db0f1e5654531784ac5c801a25d2 100644 (file)
@@ -92,6 +92,7 @@ struct sched_param {
 
 #include <asm/processor.h>
 
+struct mem_cgroup;
 struct exec_domain;
 struct futex_pi_state;
 struct robust_list_head;
@@ -810,7 +811,7 @@ static inline int above_background_load(void)
 
 struct io_context;                     /* See blkdev.h */
 #define NGROUPS_SMALL          32
-#define NGROUPS_PER_BLOCK      ((int)(PAGE_SIZE / sizeof(gid_t)))
+#define NGROUPS_PER_BLOCK      ((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
 struct group_info {
        int ngroups;
        atomic_t usage;
index 71b6df2516a68bf103d7e2ce82b82e93c9247284..59c81b708562880c845ff5080b7d173aef7ab386 100644 (file)
@@ -37,7 +37,6 @@ struct cyclades_port {
        int                     ignore_status_mask;
        int                     close_delay;
        int                     IER;    /* Interrupt Enable Register */
-       unsigned long           event;
        unsigned long           last_active;
        int                     count;  /* # of fd on device */
        int                     x_char; /* to be pushed out ASAP */
@@ -49,7 +48,6 @@ struct cyclades_port {
        int                     xmit_cnt;
         int                     default_threshold;
         int                     default_timeout;
-       struct work_struct      tqueue;
        wait_queue_head_t       open_wait;
        wait_queue_head_t       close_wait;
         struct cyclades_monitor mon;
@@ -67,18 +65,6 @@ struct cyclades_port {
 #define CYGETDEFTIMEOUT         0x435908
 #define CYSETDEFTIMEOUT         0x435909
 
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at cy interrupt time.
- */
-#define Cy_EVENT_READ_PROCESS  0
-#define Cy_EVENT_WRITE_WAKEUP  1
-#define Cy_EVENT_HANGUP                2
-#define Cy_EVENT_BREAK         3
-#define Cy_EVENT_OPEN_WAKEUP   4
-
-
-
 #define CyMaxChipsPerCard 1
 
 /**** cd2401 registers ****/
index eeaed921a1dc02d02f3a61cec5ea0c62873ecfad..eca6235a46c0b1b89d951a90216b132c6a21cfb7 100644 (file)
@@ -3,7 +3,11 @@
 
 #include <linux/ipc.h>
 #include <linux/errno.h>
+#ifdef __KERNEL__
 #include <asm/page.h>
+#else
+#include <unistd.h>
+#endif
 
 /*
  * SHMMAX, SHMMNI and SHMALL are upper limits are defaults which can
 #define SHMMAX 0x2000000                /* max shared seg size (bytes) */
 #define SHMMIN 1                        /* min shared seg size (bytes) */
 #define SHMMNI 4096                     /* max num of segs system wide */
+#ifdef __KERNEL__
 #define SHMALL (SHMMAX/PAGE_SIZE*(SHMMNI/16)) /* max shm system wide (pages) */
+#else
+#define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16))
+#endif
 #define SHMSEG SHMMNI                   /* max shared segs per process */
 
 #ifdef __KERNEL__
index 0ae338866240dee807f7f35a5f8280ebe1aa15b2..7e095147656cfac8320faab052f5574e79cd6f13 100644 (file)
@@ -371,6 +371,8 @@ int unhandled_signal(struct task_struct *tsk, int sig);
        (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
         (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
 
+void signals_init(void);
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SIGNAL_H */
index 9e3aaad6fe4dd894f5baa6d70730dde5cd385dc5..932a9efee8a5c7c9508b6c6a4f1caf565069825e 100644 (file)
@@ -70,6 +70,8 @@ extern unsigned long sm501_gpio_get(struct device *dev,
 #define SM501FB_FLAG_DISABLE_AT_EXIT   (1<<1)
 #define SM501FB_FLAG_USE_HWCURSOR      (1<<2)
 #define SM501FB_FLAG_USE_HWACCEL       (1<<3)
+#define SM501FB_FLAG_PANEL_USE_FPEN    (1<<4)
+#define SM501FB_FLAG_PANEL_USE_VBIASEN (1<<5)
 
 struct sm501_platdata_fbsub {
        struct fb_videomode     *def_mode;
index e18f5c23b9301eddd5e37dc9fce527ac63c47335..9d5da8b2ccf94f7e7211ccbff59edff11626bce0 100644 (file)
@@ -373,6 +373,15 @@ void ssb_pcihost_set_power_state(struct ssb_device *sdev, pci_power_t state)
        if (sdev->bus->bustype == SSB_BUSTYPE_PCI)
                pci_set_power_state(sdev->bus->host_pci, state);
 }
+#else
+static inline void ssb_pcihost_unregister(struct pci_driver *driver)
+{
+}
+
+static inline
+void ssb_pcihost_set_power_state(struct ssb_device *sdev, pci_power_t state)
+{
+}
 #endif /* CONFIG_SSB_PCIHOST */
 
 
index 94b4a10b912f94661e3dba9c568d1ecf183abf40..0424d75a5aaa497638e4104aa7c423d6e377256a 100644 (file)
@@ -95,7 +95,6 @@ struct stlport {
        struct tty_struct       *tty;
        wait_queue_head_t       open_wait;
        wait_queue_head_t       close_wait;
-       struct work_struct      tqueue;
        comstats_t              stats;
        struct stlrq            tx;
 };
index 353153ea0bd5cc88ba03ab48959cc0a281a95e8b..3ca5c4bd6d3f5dc6002075c2097c76dbb4e78ad2 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/linkage.h>
 #include <linux/mmzone.h>
 #include <linux/list.h>
+#include <linux/memcontrol.h>
 #include <linux/sched.h>
 
 #include <asm/atomic.h>
@@ -182,6 +183,9 @@ extern void swap_setup(void);
 /* linux/mm/vmscan.c */
 extern unsigned long try_to_free_pages(struct zone **zones, int order,
                                        gfp_t gfp_mask);
+extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
+                                                       gfp_t gfp_mask);
+extern int __isolate_lru_page(struct page *page, int mode);
 extern unsigned long shrink_all_memory(unsigned long nr_pages);
 extern int vm_swappiness;
 extern int remove_mapping(struct address_space *mapping, struct page *page);
index 24c6a2b59511edbe9ba01d22ba265a202645bed7..8ea3e71ba7fa8ff17d8de5587f482450c349ef36 100644 (file)
@@ -244,6 +244,8 @@ extern int do_adjtimex(struct timex *);
 /* Don't use! Compatibility define for existing users. */
 #define tickadj        (500/HZ ? : 1)
 
+int read_current_timer(unsigned long *timer_val);
+
 #endif /* KERNEL */
 
 #endif /* LINUX_TIMEX_H */
index 402de892b3edcdd0ae3bbf16892100e5c5570915..dd8e08fe88551a3d9c9ca2529226bfa55631e69b 100644 (file)
  */
 #define __DISABLED_CHAR '\0'
 
-/*
- * This is the flip buffer used for the tty driver.  The buffer is
- * located in the tty structure, and is used as a high speed interface
- * between the tty driver and the tty line discipline.
- */
-#define TTY_FLIPBUF_SIZE 512
-
 struct tty_buffer {
        struct tty_buffer *next;
        char *char_buf_ptr;
@@ -74,7 +67,6 @@ struct tty_buffer {
 
 struct tty_bufhead {
        struct delayed_work work;
-       struct semaphore pty_sem;
        spinlock_t lock;
        struct tty_buffer *head;        /* Queue head */
        struct tty_buffer *tail;        /* Active buffer */
index feb5e99a1079c97c0854669fcf46fcca595ab5f3..9448ffbdcbf62937047a69f1281116f133d5c079 100644 (file)
@@ -77,6 +77,7 @@ void change_console(struct vc_data *new_vc);
 void reset_vc(struct vc_data *vc);
 extern int unbind_con_driver(const struct consw *csw, int first, int last,
                             int deflt);
+int vty_init(void);
 
 /*
  * vc_screen.c shares this temporary buffer with the console write code so that
diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h
new file mode 100644 (file)
index 0000000..9797fec
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * w1-gpio interface to platform code
+ *
+ * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+#ifndef _LINUX_W1_GPIO_H
+#define _LINUX_W1_GPIO_H
+
+/**
+ * struct w1_gpio_platform_data - Platform-dependent data for w1-gpio
+ * @pin: GPIO pin to use
+ * @is_open_drain: GPIO pin is configured as open drain
+ */
+struct w1_gpio_platform_data {
+       unsigned int pin;
+       unsigned int is_open_drain:1;
+};
+
+#endif /* _LINUX_W1_GPIO_H */
index 625346c47ee2e276dd6eb413a96672bbb75014fb..585eb4496990d7a6c32951e301aaf192b09ca244 100644 (file)
@@ -124,6 +124,7 @@ enum {
        P9_DMSOCKET = 0x00100000,
        P9_DMSETUID = 0x00080000,
        P9_DMSETGID = 0x00040000,
+       P9_DMSETVTX = 0x00010000,
 };
 
 /* qid.types */
index 9b9221a213920a8d18504b82559d050cb732742d..e52f93d9ac5fca1dccdbe66a256b2d1b241f1e75 100644 (file)
@@ -3,6 +3,7 @@
  *
  * 9P Client Definitions
  *
+ *  Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
  *  Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -29,6 +30,7 @@ struct p9_client {
        spinlock_t lock; /* protect client structure */
        int msize;
        unsigned char dotu;
+       struct p9_trans_module *trans_mod;
        struct p9_trans *trans;
        struct p9_conn *conn;
 
@@ -52,8 +54,7 @@ struct p9_fid {
        struct list_head dlist; /* list of all fids attached to a dentry */
 };
 
-struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
-                                                               int dotu);
+struct p9_client *p9_client_create(const char *dev_name, char *options);
 void p9_client_destroy(struct p9_client *clnt);
 void p9_client_disconnect(struct p9_client *clnt);
 struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
diff --git a/include/net/9p/conn.h b/include/net/9p/conn.h
deleted file mode 100644 (file)
index 756d878..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * include/net/9p/conn.h
- *
- * Connection Definitions
- *
- *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2
- *  as published by the Free Software Foundation.
- *
- *  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:
- *  Free Software Foundation
- *  51 Franklin Street, Fifth Floor
- *  Boston, MA  02111-1301  USA
- *
- */
-
-#ifndef NET_9P_CONN_H
-#define NET_9P_CONN_H
-
-#undef P9_NONBLOCK
-
-struct p9_conn;
-struct p9_req;
-
-/**
- * p9_mux_req_callback - callback function that is called when the
- * response of a request is received. The callback is called from
- * a workqueue and shouldn't block.
- *
- * @req - request
- * @a - the pointer that was specified when the request was send to be
- *      passed to the callback
- */
-typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
-
-struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize,
-                                                       unsigned char *dotu);
-void p9_conn_destroy(struct p9_conn *);
-int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc);
-
-#ifdef P9_NONBLOCK
-int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
-       p9_conn_req_callback cb, void *a);
-#endif /* P9_NONBLOCK */
-
-void p9_conn_cancel(struct p9_conn *m, int err);
-
-#endif /* NET_9P_CONN_H */
index 9dd4a05619a886c7bd7fa79fff3aa53315fcb4cd..d2209ae9d18b1a94a61e14ff00c4d6e0d2f1c638 100644 (file)
@@ -4,7 +4,7 @@
  * Transport Definition
  *
  *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ *  Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
@@ -34,11 +34,12 @@ enum p9_trans_status {
 
 struct p9_trans {
        enum p9_trans_status status;
+       int msize;
+       unsigned char extended;
        void *priv;
-       int (*write) (struct p9_trans *, void *, int);
-       int (*read) (struct p9_trans *, void *, int);
        void (*close) (struct p9_trans *);
-       unsigned int (*poll)(struct p9_trans *, struct poll_table_struct *);
+       int (*rpc) (struct p9_trans *t, struct p9_fcall *tc,
+                                                       struct p9_fcall **rc);
 };
 
 struct p9_trans_module {
@@ -46,7 +47,7 @@ struct p9_trans_module {
        char *name;             /* name of transport */
        int maxsize;            /* max message size of transport */
        int def;                /* this transport should be default */
-       struct p9_trans * (*create)(const char *devname, char *options);
+       struct p9_trans * (*create)(const char *, char *, int, unsigned char);
 };
 
 void v9fs_register_trans(struct p9_trans_module *m);
index 4eea63761a3f481fa8f6dd9ed5259056fee71668..336c20db87f817f2d6667e02b5a05b1592fb3148 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __ATMEL_LCDC_H__
 #define __ATMEL_LCDC_H__
 
- /* LCD Controller info data structure */
+ /* LCD Controller info data structure, stored in device platform_data */
 struct atmel_lcdfb_info {
        spinlock_t              lock;
        struct fb_info          *info;
@@ -33,7 +33,14 @@ struct atmel_lcdfb_info {
        struct platform_device  *pdev;
        struct clk              *bus_clk;
        struct clk              *lcdc_clk;
-       unsigned int            default_bpp;
+
+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+       struct backlight_device *backlight;
+       u8                      bl_power;
+#endif
+       bool                    lcdcon_is_backlight;
+
+       u8                      default_bpp;
        unsigned int            default_lcdcon2;
        unsigned int            default_dmacon;
        void (*atmel_lcdfb_power_control)(int on);
@@ -115,20 +122,20 @@ struct atmel_lcdfb_info {
 #define                ATMEL_LCDC_MEMOR_LITTLE         (1 << 31)
 
 #define ATMEL_LCDC_TIM1                0x0808
-#define        ATMEL_LCDC_VFP          (0xff <<  0)
+#define        ATMEL_LCDC_VFP          (0xffU <<  0)
 #define        ATMEL_LCDC_VBP_OFFSET           8
-#define        ATMEL_LCDC_VBP          (0xff <<  ATMEL_LCDC_VBP_OFFSET)
+#define        ATMEL_LCDC_VBP          (0xffU <<  ATMEL_LCDC_VBP_OFFSET)
 #define        ATMEL_LCDC_VPW_OFFSET           16
-#define        ATMEL_LCDC_VPW          (0x3f << ATMEL_LCDC_VPW_OFFSET)
+#define        ATMEL_LCDC_VPW          (0x3fU << ATMEL_LCDC_VPW_OFFSET)
 #define        ATMEL_LCDC_VHDLY_OFFSET         24
-#define        ATMEL_LCDC_VHDLY        (0xf  << ATMEL_LCDC_VHDLY_OFFSET)
+#define        ATMEL_LCDC_VHDLY        (0xfU  << ATMEL_LCDC_VHDLY_OFFSET)
 
 #define ATMEL_LCDC_TIM2                0x080c
-#define        ATMEL_LCDC_HBP          (0xff  <<  0)
+#define        ATMEL_LCDC_HBP          (0xffU  <<  0)
 #define        ATMEL_LCDC_HPW_OFFSET           8
-#define        ATMEL_LCDC_HPW          (0x3f  <<  ATMEL_LCDC_HPW_OFFSET)
+#define        ATMEL_LCDC_HPW          (0x3fU  <<  ATMEL_LCDC_HPW_OFFSET)
 #define        ATMEL_LCDC_HFP_OFFSET           21
-#define        ATMEL_LCDC_HFP          (0x7ff << ATMEL_LCDC_HFP_OFFSET)
+#define        ATMEL_LCDC_HFP          (0x7ffU << ATMEL_LCDC_HFP_OFFSET)
 
 #define ATMEL_LCDC_LCDFRMCFG   0x0810
 #define        ATMEL_LCDC_LINEVAL      (0x7ff <<  0)
index 87f50df58893ef83c64d2797c934323df08cc9c3..95ac2657b0f452d71590746a493d6b8960068006 100644 (file)
@@ -369,6 +369,13 @@ config CGROUP_CPUACCT
          Provides a simple Resource Controller for monitoring the
          total CPU consumed by the tasks in a cgroup
 
+config RESOURCE_COUNTERS
+       bool "Resource counters"
+       help
+         This option enables controller independent resource accounting
+          infrastructure that works with cgroups
+       depends on CGROUPS
+
 config SYSFS_DEPRECATED
        bool "Create deprecated sysfs files"
        depends on SYSFS
@@ -390,6 +397,13 @@ config SYSFS_DEPRECATED
          If you are using a distro that was released in 2006 or later,
          it should be safe to say N here.
 
+config CGROUP_MEM_CONT
+       bool "Memory controller for cgroups"
+       depends on CGROUPS && RESOURCE_COUNTERS
+       help
+         Provides a memory controller that manages both page cache and
+         RSS memory.
+
 config PROC_PID_CPUSET
        bool "Include legacy /proc/<pid>/cpuset file"
        depends on CPUSETS
@@ -541,6 +555,18 @@ config ELF_CORE
        help
          Enable support for generating core dumps. Disabling saves about 4k.
 
+config COMPAT_BRK
+       bool "Disable heap randomization"
+       default y
+       help
+         Randomizing heap placement makes heap exploits harder, but it
+         also breaks ancient binaries (including anything libc5 based).
+         This option changes the bootup default to heap randomization
+         disabled, and can be overriden runtime by setting
+         /proc/sys/kernel/randomize_va_space to 2.
+
+         On non-ancient distros (post-2000 ones) Y is usually a safe choice.
+
 config BASE_FULL
        default y
        bool "Enable full-sized data structures for core" if EMBEDDED
index 2d3d73bd4ce13b18dcbe6d9ebd63efe1cd70c073..ecb3822d4f70ed177c45318c31aeaf8f58b1273a 100644 (file)
@@ -7,8 +7,7 @@
 #include <linux/jiffies.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-
-#include <asm/timex.h>
+#include <linux/timex.h>
 
 unsigned long preset_lpj;
 static int __init lpj_setup(char *str)
@@ -29,7 +28,7 @@ __setup("lpj=", lpj_setup);
 #define DELAY_CALIBRATION_TICKS                        ((HZ < 100) ? 1 : (HZ/100))
 #define MAX_DIRECT_CALIBRATION_RETRIES         5
 
-static unsigned long __devinit calibrate_delay_direct(void)
+static unsigned long __cpuinit calibrate_delay_direct(void)
 {
        unsigned long pre_start, start, post_start;
        unsigned long pre_end, end, post_end;
@@ -102,7 +101,7 @@ static unsigned long __devinit calibrate_delay_direct(void)
        return 0;
 }
 #else
-static unsigned long __devinit calibrate_delay_direct(void) {return 0;}
+static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
 #endif
 
 /*
@@ -112,7 +111,7 @@ static unsigned long __devinit calibrate_delay_direct(void) {return 0;}
  */
 #define LPS_PREC 8
 
-void __devinit calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
 {
        unsigned long ticks, loopbit;
        int lps_precision = LPS_PREC;
index 1161dfd7b0d3d23a4f9968c973a5f578b42c341d..f86573126f83fe76c3b87d85342786cb5a158204 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mount.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/fs.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
@@ -18,8 +19,6 @@
 
 #include "do_mounts.h"
 
-extern int get_filesystem_list(char * buf);
-
 int __initdata rd_doload;      /* 1 = load RAM disk, 0 = don't load */
 
 int root_mountflags = MS_RDONLY | MS_SILENT;
index 1db02a0025db2a5f805ed78d7f88a8cf30a230df..d53fee8d8604a5514889bfcd93acee4dd882fae0 100644 (file)
@@ -503,7 +503,6 @@ static int __init retain_initrd_param(char *str)
 __setup("retain_initrd", retain_initrd_param);
 
 extern char __initramfs_start[], __initramfs_end[];
-#ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/initrd.h>
 #include <linux/kexec.h>
 
@@ -539,15 +538,12 @@ skip:
        initrd_end = 0;
 }
 
-#endif
-
 static int __init populate_rootfs(void)
 {
        char *err = unpack_to_rootfs(__initramfs_start,
                         __initramfs_end - __initramfs_start, 0);
        if (err)
                panic(err);
-#ifdef CONFIG_BLK_DEV_INITRD
        if (initrd_start) {
 #ifdef CONFIG_BLK_DEV_RAM
                int fd;
@@ -579,7 +575,6 @@ static int __init populate_rootfs(void)
                free_initrd();
 #endif
        }
-#endif
        return 0;
 }
 rootfs_initcall(populate_rootfs);
index cb81ed116f62b3cadbde986e508081295c0446d9..c691f5f7fc27b40ea6b2df39e2fef9ac52b4cd0a 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/device.h>
 #include <linux/kthread.h>
 #include <linux/sched.h>
+#include <linux/signal.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -83,7 +84,6 @@ extern void init_IRQ(void);
 extern void fork_init(unsigned long);
 extern void mca_init(void);
 extern void sbus_init(void);
-extern void signals_init(void);
 extern void pidhash_init(void);
 extern void pidmap_init(void);
 extern void prio_tree_init(void);
index fdf3db5731ce8df2cfd038f40c69710243d85338..ec0c724054b95ce733eee1510d044df7d95bea20 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -105,6 +105,7 @@ int msg_init_ns(struct ipc_namespace *ns)
 void msg_exit_ns(struct ipc_namespace *ns)
 {
        struct msg_queue *msq;
+       struct kern_ipc_perm *perm;
        int next_id;
        int total, in_use;
 
@@ -113,10 +114,11 @@ void msg_exit_ns(struct ipc_namespace *ns)
        in_use = msg_ids(ns).in_use;
 
        for (total = 0, next_id = 0; total < in_use; next_id++) {
-               msq = idr_find(&msg_ids(ns).ipcs_idr, next_id);
-               if (msq == NULL)
+               perm = idr_find(&msg_ids(ns).ipcs_idr, next_id);
+               if (perm == NULL)
                        continue;
-               ipc_lock_by_ptr(&msq->q_perm);
+               ipc_lock_by_ptr(perm);
+               msq = container_of(perm, struct msg_queue, q_perm);
                freeque(ns, msq);
                total++;
        }
@@ -144,6 +146,9 @@ static inline struct msg_queue *msg_lock_check_down(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check_down(&msg_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct msg_queue *)ipcp;
+
        return container_of(ipcp, struct msg_queue, q_perm);
 }
 
@@ -155,6 +160,9 @@ static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id)
 {
        struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct msg_queue *)ipcp;
+
        return container_of(ipcp, struct msg_queue, q_perm);
 }
 
@@ -163,6 +171,9 @@ static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct msg_queue *)ipcp;
+
        return container_of(ipcp, struct msg_queue, q_perm);
 }
 
index 35952c0bae4629cac017c4c62623c91a022ebee5..d65e285b7e309de03d68cbef348929d0b23f961f 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -143,6 +143,7 @@ int sem_init_ns(struct ipc_namespace *ns)
 void sem_exit_ns(struct ipc_namespace *ns)
 {
        struct sem_array *sma;
+       struct kern_ipc_perm *perm;
        int next_id;
        int total, in_use;
 
@@ -151,10 +152,11 @@ void sem_exit_ns(struct ipc_namespace *ns)
        in_use = sem_ids(ns).in_use;
 
        for (total = 0, next_id = 0; total < in_use; next_id++) {
-               sma = idr_find(&sem_ids(ns).ipcs_idr, next_id);
-               if (sma == NULL)
+               perm = idr_find(&sem_ids(ns).ipcs_idr, next_id);
+               if (perm == NULL)
                        continue;
-               ipc_lock_by_ptr(&sma->sem_perm);
+               ipc_lock_by_ptr(perm);
+               sma = container_of(perm, struct sem_array, sem_perm);
                freeary(ns, sma);
                total++;
        }
@@ -181,6 +183,9 @@ static inline struct sem_array *sem_lock_check_down(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check_down(&sem_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct sem_array *)ipcp;
+
        return container_of(ipcp, struct sem_array, sem_perm);
 }
 
@@ -192,6 +197,9 @@ static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id)
 {
        struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct sem_array *)ipcp;
+
        return container_of(ipcp, struct sem_array, sem_perm);
 }
 
@@ -200,6 +208,9 @@ static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct sem_array *)ipcp;
+
        return container_of(ipcp, struct sem_array, sem_perm);
 }
 
index 3818fae625c5252363380fa9c7a521e8b5c1a7d1..65c3a294aba5cf265823f3d6f369b7b206643d22 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -111,6 +111,7 @@ int shm_init_ns(struct ipc_namespace *ns)
 void shm_exit_ns(struct ipc_namespace *ns)
 {
        struct shmid_kernel *shp;
+       struct kern_ipc_perm *perm;
        int next_id;
        int total, in_use;
 
@@ -119,10 +120,11 @@ void shm_exit_ns(struct ipc_namespace *ns)
        in_use = shm_ids(ns).in_use;
 
        for (total = 0, next_id = 0; total < in_use; next_id++) {
-               shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
-               if (shp == NULL)
+               perm = idr_find(&shm_ids(ns).ipcs_idr, next_id);
+               if (perm == NULL)
                        continue;
-               ipc_lock_by_ptr(&shp->shm_perm);
+               ipc_lock_by_ptr(perm);
+               shp = container_of(perm, struct shmid_kernel, shm_perm);
                do_shm_rmid(ns, shp);
                total++;
        }
@@ -149,6 +151,9 @@ static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct shmid_kernel *)ipcp;
+
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -158,6 +163,9 @@ static inline struct shmid_kernel *shm_lock_check_down(
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct shmid_kernel *)ipcp;
+
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -169,6 +177,9 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
 {
        struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct shmid_kernel *)ipcp;
+
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -177,6 +188,9 @@ static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct shmid_kernel *)ipcp;
+
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
index 1aa0ebf71bac7e5c30559eb0f60a89bdc6688efb..76c1f3461e22603496652242299af80d0e17d860 100644 (file)
@@ -802,8 +802,8 @@ struct ipc_proc_iter {
 /*
  * This routine locks the ipc structure found at least at position pos.
  */
-struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
-                                       loff_t *new_pos)
+static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
+                                             loff_t *new_pos)
 {
        struct kern_ipc_perm *ipc;
        int total, id;
index 135a1b943446eafe72a1da7f272386749b9b0f35..685697c0a1818bbddeac651cabb4ba14f7fddb54 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_CGROUP_DEBUG) += cgroup_debug.o
 obj-$(CONFIG_CPUSETS) += cpuset.o
 obj-$(CONFIG_CGROUP_NS) += ns_cgroup.o
 obj-$(CONFIG_IKCONFIG) += configs.o
+obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
 obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
 obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
index 1a3c23936d43d99ec3d429123c95182a94de0c02..4766bb65e4d9c8e060c9db3ceebb64a2da33df0b 100644 (file)
@@ -141,7 +141,7 @@ enum {
        ROOT_NOPREFIX, /* mounted subsystems have no named prefix */
 };
 
-inline int cgroup_is_releasable(const struct cgroup *cgrp)
+static int cgroup_is_releasable(const struct cgroup *cgrp)
 {
        const int bits =
                (1 << CGRP_RELEASABLE) |
@@ -149,7 +149,7 @@ inline int cgroup_is_releasable(const struct cgroup *cgrp)
        return (cgrp->flags & bits) == bits;
 }
 
-inline int notify_on_release(const struct cgroup *cgrp)
+static int notify_on_release(const struct cgroup *cgrp)
 {
        return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
 }
@@ -489,7 +489,7 @@ static struct css_set *find_css_set(
  * Any task can increment and decrement the count field without lock.
  * So in general, code holding cgroup_mutex can't rely on the count
  * field not changing.  However, if the count goes to zero, then only
- * attach_task() can increment it again.  Because a count of zero
+ * cgroup_attach_task() can increment it again.  Because a count of zero
  * means that no tasks are currently attached, therefore there is no
  * way a task attached to that cgroup can fork (the other way to
  * increment the count).  So code holding cgroup_mutex can safely
@@ -520,17 +520,17 @@ static struct css_set *find_css_set(
  *     The task_lock() exception
  *
  * The need for this exception arises from the action of
- * attach_task(), which overwrites one tasks cgroup pointer with
+ * cgroup_attach_task(), which overwrites one tasks cgroup pointer with
  * another.  It does so using cgroup_mutexe, however there are
  * several performance critical places that need to reference
  * task->cgroup without the expense of grabbing a system global
  * mutex.  Therefore except as noted below, when dereferencing or, as
- * in attach_task(), modifying a task'ss cgroup pointer we use
+ * in cgroup_attach_task(), modifying a task'ss cgroup pointer we use
  * task_lock(), which acts on a spinlock (task->alloc_lock) already in
  * the task_struct routinely used for such matters.
  *
  * P.S.  One more locking exception.  RCU is used to guard the
- * update of a tasks cgroup pointer by attach_task()
+ * update of a tasks cgroup pointer by cgroup_attach_task()
  */
 
 /**
@@ -586,11 +586,27 @@ static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
        return inode;
 }
 
+/*
+ * Call subsys's pre_destroy handler.
+ * This is called before css refcnt check.
+ */
+
+static void cgroup_call_pre_destroy(struct cgroup *cgrp)
+{
+       struct cgroup_subsys *ss;
+       for_each_subsys(cgrp->root, ss)
+               if (ss->pre_destroy && cgrp->subsys[ss->subsys_id])
+                       ss->pre_destroy(ss, cgrp);
+       return;
+}
+
+
 static void cgroup_diput(struct dentry *dentry, struct inode *inode)
 {
        /* is dentry a directory ? if so, kfree() associated cgroup */
        if (S_ISDIR(inode->i_mode)) {
                struct cgroup *cgrp = dentry->d_fsdata;
+               struct cgroup_subsys *ss;
                BUG_ON(!(cgroup_is_removed(cgrp)));
                /* It's possible for external users to be holding css
                 * reference counts on a cgroup; css_put() needs to
@@ -599,6 +615,23 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
                 * queue the cgroup to be handled by the release
                 * agent */
                synchronize_rcu();
+
+               mutex_lock(&cgroup_mutex);
+               /*
+                * Release the subsystem state objects.
+                */
+               for_each_subsys(cgrp->root, ss) {
+                       if (cgrp->subsys[ss->subsys_id])
+                               ss->destroy(ss, cgrp);
+               }
+
+               cgrp->root->number_of_cgroups--;
+               mutex_unlock(&cgroup_mutex);
+
+               /* Drop the active superblock reference that we took when we
+                * created the cgroup */
+               deactivate_super(cgrp->root->sb);
+
                kfree(cgrp);
        }
        iput(inode);
@@ -1161,7 +1194,7 @@ static void get_first_subsys(const struct cgroup *cgrp,
  * Call holding cgroup_mutex.  May take task_lock of
  * the task 'pid' during call.
  */
-static int attach_task(struct cgroup *cgrp, struct task_struct *tsk)
+int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 {
        int retval = 0;
        struct cgroup_subsys *ss;
@@ -1181,9 +1214,8 @@ static int attach_task(struct cgroup *cgrp, struct task_struct *tsk)
        for_each_subsys(root, ss) {
                if (ss->can_attach) {
                        retval = ss->can_attach(ss, cgrp, tsk);
-                       if (retval) {
+                       if (retval)
                                return retval;
-                       }
                }
        }
 
@@ -1192,9 +1224,8 @@ static int attach_task(struct cgroup *cgrp, struct task_struct *tsk)
         * based on its final set of cgroups
         */
        newcg = find_css_set(cg, cgrp);
-       if (!newcg) {
+       if (!newcg)
                return -ENOMEM;
-       }
 
        task_lock(tsk);
        if (tsk->flags & PF_EXITING) {
@@ -1214,9 +1245,8 @@ static int attach_task(struct cgroup *cgrp, struct task_struct *tsk)
        write_unlock(&css_set_lock);
 
        for_each_subsys(root, ss) {
-               if (ss->attach) {
+               if (ss->attach)
                        ss->attach(ss, cgrp, oldcgrp, tsk);
-               }
        }
        set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
        synchronize_rcu();
@@ -1239,7 +1269,7 @@ static int attach_task_by_pid(struct cgroup *cgrp, char *pidbuf)
 
        if (pid) {
                rcu_read_lock();
-               tsk = find_task_by_pid(pid);
+               tsk = find_task_by_vpid(pid);
                if (!tsk || tsk->flags & PF_EXITING) {
                        rcu_read_unlock();
                        return -ESRCH;
@@ -1257,7 +1287,7 @@ static int attach_task_by_pid(struct cgroup *cgrp, char *pidbuf)
                get_task_struct(tsk);
        }
 
-       ret = attach_task(cgrp, tsk);
+       ret = cgroup_attach_task(cgrp, tsk);
        put_task_struct(tsk);
        return ret;
 }
@@ -1329,9 +1359,14 @@ static ssize_t cgroup_common_file_write(struct cgroup *cgrp,
                goto out1;
        }
        buffer[nbytes] = 0;     /* nul-terminate */
+       strstrip(buffer);       /* strip -just- trailing whitespace */
 
        mutex_lock(&cgroup_mutex);
 
+       /*
+        * This was already checked for in cgroup_file_write(), but
+        * check again now we're holding cgroup_mutex.
+        */
        if (cgroup_is_removed(cgrp)) {
                retval = -ENODEV;
                goto out2;
@@ -1349,24 +1384,9 @@ static ssize_t cgroup_common_file_write(struct cgroup *cgrp,
                        clear_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
                break;
        case FILE_RELEASE_AGENT:
-       {
-               struct cgroupfs_root *root = cgrp->root;
-               /* Strip trailing newline */
-               if (nbytes && (buffer[nbytes-1] == '\n')) {
-                       buffer[nbytes-1] = 0;
-               }
-               if (nbytes < sizeof(root->release_agent_path)) {
-                       /* We never write anything other than '\0'
-                        * into the last char of release_agent_path,
-                        * so it always remains a NUL-terminated
-                        * string */
-                       strncpy(root->release_agent_path, buffer, nbytes);
-                       root->release_agent_path[nbytes] = 0;
-               } else {
-                       retval = -ENOSPC;
-               }
+               BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
+               strcpy(cgrp->root->release_agent_path, buffer);
                break;
-       }
        default:
                retval = -EINVAL;
                goto out2;
@@ -1387,7 +1407,7 @@ static ssize_t cgroup_file_write(struct file *file, const char __user *buf,
        struct cftype *cft = __d_cft(file->f_dentry);
        struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
 
-       if (!cft)
+       if (!cft || cgroup_is_removed(cgrp))
                return -ENODEV;
        if (cft->write)
                return cft->write(cgrp, cft, file, buf, nbytes, ppos);
@@ -1457,7 +1477,7 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf,
        struct cftype *cft = __d_cft(file->f_dentry);
        struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
 
-       if (!cft)
+       if (!cft || cgroup_is_removed(cgrp))
                return -ENODEV;
 
        if (cft->read)
@@ -1675,6 +1695,29 @@ static void cgroup_advance_iter(struct cgroup *cgrp,
        it->task = cg->tasks.next;
 }
 
+/*
+ * To reduce the fork() overhead for systems that are not actually
+ * using their cgroups capability, we don't maintain the lists running
+ * through each css_set to its tasks until we see the list actually
+ * used - in other words after the first call to cgroup_iter_start().
+ *
+ * The tasklist_lock is not held here, as do_each_thread() and
+ * while_each_thread() are protected by RCU.
+ */
+void cgroup_enable_task_cg_lists(void)
+{
+       struct task_struct *p, *g;
+       write_lock(&css_set_lock);
+       use_task_css_set_links = 1;
+       do_each_thread(g, p) {
+               task_lock(p);
+               if (list_empty(&p->cg_list))
+                       list_add(&p->cg_list, &p->cgroups->tasks);
+               task_unlock(p);
+       } while_each_thread(g, p);
+       write_unlock(&css_set_lock);
+}
+
 void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it)
 {
        /*
@@ -1682,18 +1725,9 @@ void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it)
         * we need to enable the list linking each css_set to its
         * tasks, and fix up all existing tasks.
         */
-       if (!use_task_css_set_links) {
-               struct task_struct *p, *g;
-               write_lock(&css_set_lock);
-               use_task_css_set_links = 1;
-               do_each_thread(g, p) {
-                       task_lock(p);
-                       if (list_empty(&p->cg_list))
-                               list_add(&p->cg_list, &p->cgroups->tasks);
-                       task_unlock(p);
-               } while_each_thread(g, p);
-               write_unlock(&css_set_lock);
-       }
+       if (!use_task_css_set_links)
+               cgroup_enable_task_cg_lists();
+
        read_lock(&css_set_lock);
        it->cg_link = &cgrp->css_sets;
        cgroup_advance_iter(cgrp, it);
@@ -1726,6 +1760,166 @@ void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it)
        read_unlock(&css_set_lock);
 }
 
+static inline int started_after_time(struct task_struct *t1,
+                                    struct timespec *time,
+                                    struct task_struct *t2)
+{
+       int start_diff = timespec_compare(&t1->start_time, time);
+       if (start_diff > 0) {
+               return 1;
+       } else if (start_diff < 0) {
+               return 0;
+       } else {
+               /*
+                * Arbitrarily, if two processes started at the same
+                * time, we'll say that the lower pointer value
+                * started first. Note that t2 may have exited by now
+                * so this may not be a valid pointer any longer, but
+                * that's fine - it still serves to distinguish
+                * between two tasks started (effectively) simultaneously.
+                */
+               return t1 > t2;
+       }
+}
+
+/*
+ * This function is a callback from heap_insert() and is used to order
+ * the heap.
+ * In this case we order the heap in descending task start time.
+ */
+static inline int started_after(void *p1, void *p2)
+{
+       struct task_struct *t1 = p1;
+       struct task_struct *t2 = p2;
+       return started_after_time(t1, &t2->start_time, t2);
+}
+
+/**
+ * cgroup_scan_tasks - iterate though all the tasks in a cgroup
+ * @scan: struct cgroup_scanner containing arguments for the scan
+ *
+ * Arguments include pointers to callback functions test_task() and
+ * process_task().
+ * Iterate through all the tasks in a cgroup, calling test_task() for each,
+ * and if it returns true, call process_task() for it also.
+ * The test_task pointer may be NULL, meaning always true (select all tasks).
+ * Effectively duplicates cgroup_iter_{start,next,end}()
+ * but does not lock css_set_lock for the call to process_task().
+ * The struct cgroup_scanner may be embedded in any structure of the caller's
+ * creation.
+ * It is guaranteed that process_task() will act on every task that
+ * is a member of the cgroup for the duration of this call. This
+ * function may or may not call process_task() for tasks that exit
+ * or move to a different cgroup during the call, or are forked or
+ * move into the cgroup during the call.
+ *
+ * Note that test_task() may be called with locks held, and may in some
+ * situations be called multiple times for the same task, so it should
+ * be cheap.
+ * If the heap pointer in the struct cgroup_scanner is non-NULL, a heap has been
+ * pre-allocated and will be used for heap operations (and its "gt" member will
+ * be overwritten), else a temporary heap will be used (allocation of which
+ * may cause this function to fail).
+ */
+int cgroup_scan_tasks(struct cgroup_scanner *scan)
+{
+       int retval, i;
+       struct cgroup_iter it;
+       struct task_struct *p, *dropped;
+       /* Never dereference latest_task, since it's not refcounted */
+       struct task_struct *latest_task = NULL;
+       struct ptr_heap tmp_heap;
+       struct ptr_heap *heap;
+       struct timespec latest_time = { 0, 0 };
+
+       if (scan->heap) {
+               /* The caller supplied our heap and pre-allocated its memory */
+               heap = scan->heap;
+               heap->gt = &started_after;
+       } else {
+               /* We need to allocate our own heap memory */
+               heap = &tmp_heap;
+               retval = heap_init(heap, PAGE_SIZE, GFP_KERNEL, &started_after);
+               if (retval)
+                       /* cannot allocate the heap */
+                       return retval;
+       }
+
+ again:
+       /*
+        * Scan tasks in the cgroup, using the scanner's "test_task" callback
+        * to determine which are of interest, and using the scanner's
+        * "process_task" callback to process any of them that need an update.
+        * Since we don't want to hold any locks during the task updates,
+        * gather tasks to be processed in a heap structure.
+        * The heap is sorted by descending task start time.
+        * If the statically-sized heap fills up, we overflow tasks that
+        * started later, and in future iterations only consider tasks that
+        * started after the latest task in the previous pass. This
+        * guarantees forward progress and that we don't miss any tasks.
+        */
+       heap->size = 0;
+       cgroup_iter_start(scan->cg, &it);
+       while ((p = cgroup_iter_next(scan->cg, &it))) {
+               /*
+                * Only affect tasks that qualify per the caller's callback,
+                * if he provided one
+                */
+               if (scan->test_task && !scan->test_task(p, scan))
+                       continue;
+               /*
+                * Only process tasks that started after the last task
+                * we processed
+                */
+               if (!started_after_time(p, &latest_time, latest_task))
+                       continue;
+               dropped = heap_insert(heap, p);
+               if (dropped == NULL) {
+                       /*
+                        * The new task was inserted; the heap wasn't
+                        * previously full
+                        */
+                       get_task_struct(p);
+               } else if (dropped != p) {
+                       /*
+                        * The new task was inserted, and pushed out a
+                        * different task
+                        */
+                       get_task_struct(p);
+                       put_task_struct(dropped);
+               }
+               /*
+                * Else the new task was newer than anything already in
+                * the heap and wasn't inserted
+                */
+       }
+       cgroup_iter_end(scan->cg, &it);
+
+       if (heap->size) {
+               for (i = 0; i < heap->size; i++) {
+                       struct task_struct *p = heap->ptrs[i];
+                       if (i == 0) {
+                               latest_time = p->start_time;
+                               latest_task = p;
+                       }
+                       /* Process the task per the caller's callback */
+                       scan->process_task(p, scan);
+                       put_task_struct(p);
+               }
+               /*
+                * If we had to process any tasks at all, scan again
+                * in case some of them were in the middle of forking
+                * children that didn't get processed.
+                * Not the most efficient way to do it, but it avoids
+                * having to take callback_mutex in the fork path
+                */
+               goto again;
+       }
+       if (heap == &tmp_heap)
+               heap_free(&tmp_heap);
+       return 0;
+}
+
 /*
  * Stuff for reading the 'tasks' file.
  *
@@ -1761,7 +1955,7 @@ static int pid_array_load(pid_t *pidarray, int npids, struct cgroup *cgrp)
        while ((tsk = cgroup_iter_next(cgrp, &it))) {
                if (unlikely(n == npids))
                        break;
-               pidarray[n++] = task_pid_nr(tsk);
+               pidarray[n++] = task_pid_vnr(tsk);
        }
        cgroup_iter_end(cgrp, &it);
        return n;
@@ -2126,9 +2320,8 @@ static inline int cgroup_has_css_refs(struct cgroup *cgrp)
                 * matter, since it can only happen if the cgroup
                 * has been deleted and hence no longer needs the
                 * release agent to be called anyway. */
-               if (css && atomic_read(&css->refcnt)) {
+               if (css && atomic_read(&css->refcnt))
                        return 1;
-               }
        }
        return 0;
 }
@@ -2138,7 +2331,6 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
        struct cgroup *cgrp = dentry->d_fsdata;
        struct dentry *d;
        struct cgroup *parent;
-       struct cgroup_subsys *ss;
        struct super_block *sb;
        struct cgroupfs_root *root;
 
@@ -2157,17 +2349,19 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
        parent = cgrp->parent;
        root = cgrp->root;
        sb = root->sb;
+       /*
+        * Call pre_destroy handlers of subsys
+        */
+       cgroup_call_pre_destroy(cgrp);
+       /*
+        * Notify subsyses that rmdir() request comes.
+        */
 
        if (cgroup_has_css_refs(cgrp)) {
                mutex_unlock(&cgroup_mutex);
                return -EBUSY;
        }
 
-       for_each_subsys(root, ss) {
-               if (cgrp->subsys[ss->subsys_id])
-                       ss->destroy(ss, cgrp);
-       }
-
        spin_lock(&release_list_lock);
        set_bit(CGRP_REMOVED, &cgrp->flags);
        if (!list_empty(&cgrp->release_list))
@@ -2182,15 +2376,11 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
 
        cgroup_d_remove_dir(d);
        dput(d);
-       root->number_of_cgroups--;
 
        set_bit(CGRP_RELEASABLE, &parent->flags);
        check_for_release(parent);
 
        mutex_unlock(&cgroup_mutex);
-       /* Drop the active superblock reference that we took when we
-        * created the cgroup */
-       deactivate_super(sb);
        return 0;
 }
 
@@ -2324,7 +2514,7 @@ out:
  *  - Used for /proc/<pid>/cgroup.
  *  - No need to task_lock(tsk) on this tsk->cgroup reference, as it
  *    doesn't really matter if tsk->cgroup changes after we read it,
- *    and we take cgroup_mutex, keeping attach_task() from changing it
+ *    and we take cgroup_mutex, keeping cgroup_attach_task() from changing it
  *    anyway.  No need to check that tsk->cgroup != NULL, thanks to
  *    the_top_cgroup_hack in cgroup_exit(), which sets an exiting tasks
  *    cgroup to top_cgroup.
@@ -2435,7 +2625,7 @@ static struct file_operations proc_cgroupstats_operations = {
  * A pointer to the shared css_set was automatically copied in
  * fork.c by dup_task_struct().  However, we ignore that copy, since
  * it was not made under the protection of RCU or cgroup_mutex, so
- * might no longer be a valid cgroup pointer.  attach_task() might
+ * might no longer be a valid cgroup pointer.  cgroup_attach_task() might
  * have already changed current->cgroups, allowing the previously
  * referenced cgroup group to be removed and freed.
  *
@@ -2514,8 +2704,8 @@ void cgroup_post_fork(struct task_struct *child)
  *    attach us to a different cgroup, decrementing the count on
  *    the first cgroup that we never incremented.  But in this case,
  *    top_cgroup isn't going away, and either task has PF_EXITING set,
- *    which wards off any attach_task() attempts, or task is a failed
- *    fork, never visible to attach_task.
+ *    which wards off any cgroup_attach_task() attempts, or task is a failed
+ *    fork, never visible to cgroup_attach_task.
  *
  */
 void cgroup_exit(struct task_struct *tsk, int run_callbacks)
@@ -2655,7 +2845,7 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys)
        }
 
        /* All seems fine. Finish by moving the task into the new cgroup */
-       ret = attach_task(child, tsk);
+       ret = cgroup_attach_task(child, tsk);
        mutex_unlock(&cgroup_mutex);
 
  out_release:
index cfaf6419d817e0a387f1c39d878f342e279818b6..67b2bfe27814e248fcc481f0f6e2ccd65fb5ba55 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/pagemap.h>
-#include <linux/prio_heap.h>
 #include <linux/proc_fs.h>
 #include <linux/rcupdate.h>
 #include <linux/sched.h>
@@ -56,6 +55,8 @@
 #include <asm/atomic.h>
 #include <linux/mutex.h>
 #include <linux/kfifo.h>
+#include <linux/workqueue.h>
+#include <linux/cgroup.h>
 
 /*
  * Tracks how many cpusets are currently defined in system.
@@ -64,7 +65,7 @@
  */
 int number_of_cpusets __read_mostly;
 
-/* Retrieve the cpuset from a cgroup */
+/* Forward declare cgroup structures */
 struct cgroup_subsys cpuset_subsys;
 struct cpuset;
 
@@ -96,6 +97,9 @@ struct cpuset {
 
        /* partition number for rebuild_sched_domains() */
        int pn;
+
+       /* used for walking a cpuset heirarchy */
+       struct list_head stack_list;
 };
 
 /* Retrieve the cpuset for a cgroup */
@@ -111,7 +115,10 @@ static inline struct cpuset *task_cs(struct task_struct *task)
        return container_of(task_subsys_state(task, cpuset_subsys_id),
                            struct cpuset, css);
 }
-
+struct cpuset_hotplug_scanner {
+       struct cgroup_scanner scan;
+       struct cgroup *to;
+};
 
 /* bits in struct cpuset flags field */
 typedef enum {
@@ -160,17 +167,17 @@ static inline int is_spread_slab(const struct cpuset *cs)
  * number, and avoid having to lock and reload mems_allowed unless
  * the cpuset they're using changes generation.
  *
- * A single, global generation is needed because attach_task() could
+ * A single, global generation is needed because cpuset_attach_task() could
  * reattach a task to a different cpuset, which must not have its
  * generation numbers aliased with those of that tasks previous cpuset.
  *
  * Generations are needed for mems_allowed because one task cannot
- * modify anothers memory placement.  So we must enable every task,
+ * modify another's memory placement.  So we must enable every task,
  * on every visit to __alloc_pages(), to efficiently check whether
  * its current->cpuset->mems_allowed has changed, requiring an update
  * of its current->mems_allowed.
  *
- * Since cpuset_mems_generation is guarded by manage_mutex,
+ * Since writes to cpuset_mems_generation are guarded by the cgroup lock
  * there is no need to mark it atomic.
  */
 static int cpuset_mems_generation;
@@ -182,17 +189,20 @@ static struct cpuset top_cpuset = {
 };
 
 /*
- * We have two global cpuset mutexes below.  They can nest.
- * It is ok to first take manage_mutex, then nest callback_mutex.  We also
- * require taking task_lock() when dereferencing a tasks cpuset pointer.
- * See "The task_lock() exception", at the end of this comment.
+ * There are two global mutexes guarding cpuset structures.  The first
+ * is the main control groups cgroup_mutex, accessed via
+ * cgroup_lock()/cgroup_unlock().  The second is the cpuset-specific
+ * callback_mutex, below. They can nest.  It is ok to first take
+ * cgroup_mutex, then nest callback_mutex.  We also require taking
+ * task_lock() when dereferencing a task's cpuset pointer.  See "The
+ * task_lock() exception", at the end of this comment.
  *
  * A task must hold both mutexes to modify cpusets.  If a task
- * holds manage_mutex, then it blocks others wanting that mutex,
+ * holds cgroup_mutex, then it blocks others wanting that mutex,
  * ensuring that it is the only task able to also acquire callback_mutex
  * and be able to modify cpusets.  It can perform various checks on
  * the cpuset structure first, knowing nothing will change.  It can
- * also allocate memory while just holding manage_mutex.  While it is
+ * also allocate memory while just holding cgroup_mutex.  While it is
  * performing these checks, various callback routines can briefly
  * acquire callback_mutex to query cpusets.  Once it is ready to make
  * the changes, it takes callback_mutex, blocking everyone else.
@@ -208,60 +218,16 @@ static struct cpuset top_cpuset = {
  * The task_struct fields mems_allowed and mems_generation may only
  * be accessed in the context of that task, so require no locks.
  *
- * Any task can increment and decrement the count field without lock.
- * So in general, code holding manage_mutex or callback_mutex can't rely
- * on the count field not changing.  However, if the count goes to
- * zero, then only attach_task(), which holds both mutexes, can
- * increment it again.  Because a count of zero means that no tasks
- * are currently attached, therefore there is no way a task attached
- * to that cpuset can fork (the other way to increment the count).
- * So code holding manage_mutex or callback_mutex can safely assume that
- * if the count is zero, it will stay zero.  Similarly, if a task
- * holds manage_mutex or callback_mutex on a cpuset with zero count, it
- * knows that the cpuset won't be removed, as cpuset_rmdir() needs
- * both of those mutexes.
- *
  * The cpuset_common_file_write handler for operations that modify
- * the cpuset hierarchy holds manage_mutex across the entire operation,
+ * the cpuset hierarchy holds cgroup_mutex across the entire operation,
  * single threading all such cpuset modifications across the system.
  *
  * The cpuset_common_file_read() handlers only hold callback_mutex across
  * small pieces of code, such as when reading out possibly multi-word
  * cpumasks and nodemasks.
  *
- * The fork and exit callbacks cpuset_fork() and cpuset_exit(), don't
- * (usually) take either mutex.  These are the two most performance
- * critical pieces of code here.  The exception occurs on cpuset_exit(),
- * when a task in a notify_on_release cpuset exits.  Then manage_mutex
- * is taken, and if the cpuset count is zero, a usermode call made
- * to /sbin/cpuset_release_agent with the name of the cpuset (path
- * relative to the root of cpuset file system) as the argument.
- *
- * A cpuset can only be deleted if both its 'count' of using tasks
- * is zero, and its list of 'children' cpusets is empty.  Since all
- * tasks in the system use _some_ cpuset, and since there is always at
- * least one task in the system (init), therefore, top_cpuset
- * always has either children cpusets and/or using tasks.  So we don't
- * need a special hack to ensure that top_cpuset cannot be deleted.
- *
- * The above "Tale of Two Semaphores" would be complete, but for:
- *
- *     The task_lock() exception
- *
- * The need for this exception arises from the action of attach_task(),
- * which overwrites one tasks cpuset pointer with another.  It does
- * so using both mutexes, however there are several performance
- * critical places that need to reference task->cpuset without the
- * expense of grabbing a system global mutex.  Therefore except as
- * noted below, when dereferencing or, as in attach_task(), modifying
- * a tasks cpuset pointer we use task_lock(), which acts on a spinlock
- * (task->alloc_lock) already in the task_struct routinely used for
- * such matters.
- *
- * P.S.  One more locking exception.  RCU is used to guard the
- * update of a tasks cpuset pointer by attach_task() and the
- * access of task->cpuset->mems_generation via that pointer in
- * the routine cpuset_update_task_memory_state().
+ * Accessing a task's cpuset should be done in accordance with the
+ * guidelines for accessing subsystem state in kernel/cgroup.c
  */
 
 static DEFINE_MUTEX(callback_mutex);
@@ -354,15 +320,14 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
  * Do not call this routine if in_interrupt().
  *
  * Call without callback_mutex or task_lock() held.  May be
- * called with or without manage_mutex held.  Thanks in part to
- * 'the_top_cpuset_hack', the tasks cpuset pointer will never
+ * called with or without cgroup_mutex held.  Thanks in part to
+ * 'the_top_cpuset_hack', the task's cpuset pointer will never
  * be NULL.  This routine also might acquire callback_mutex and
  * current->mm->mmap_sem during call.
  *
  * Reading current->cpuset->mems_generation doesn't need task_lock
  * to guard the current->cpuset derefence, because it is guarded
- * from concurrent freeing of current->cpuset by attach_task(),
- * using RCU.
+ * from concurrent freeing of current->cpuset using RCU.
  *
  * The rcu_dereference() is technically probably not needed,
  * as I don't actually mind if I see a new cpuset pointer but
@@ -424,7 +389,7 @@ void cpuset_update_task_memory_state(void)
  *
  * One cpuset is a subset of another if all its allowed CPUs and
  * Memory Nodes are a subset of the other, and its exclusive flags
- * are only set if the other's are set.  Call holding manage_mutex.
+ * are only set if the other's are set.  Call holding cgroup_mutex.
  */
 
 static int is_cpuset_subset(const struct cpuset *p, const struct cpuset *q)
@@ -442,7 +407,7 @@ static int is_cpuset_subset(const struct cpuset *p, const struct cpuset *q)
  * If we replaced the flag and mask values of the current cpuset
  * (cur) with those values in the trial cpuset (trial), would
  * our various subset and exclusive rules still be valid?  Presumes
- * manage_mutex held.
+ * cgroup_mutex held.
  *
  * 'cur' is the address of an actual, in-use cpuset.  Operations
  * such as list traversal that depend on the actual address of the
@@ -476,7 +441,10 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
        if (!is_cpuset_subset(trial, par))
                return -EACCES;
 
-       /* If either I or some sibling (!= me) is exclusive, we can't overlap */
+       /*
+        * If either I or some sibling (!= me) is exclusive, we can't
+        * overlap
+        */
        list_for_each_entry(cont, &par->css.cgroup->children, sibling) {
                c = cgroup_cs(cont);
                if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
@@ -732,22 +700,50 @@ static inline int started_after(void *p1, void *p2)
        return started_after_time(t1, &t2->start_time, t2);
 }
 
-/*
- * Call with manage_mutex held.  May take callback_mutex during call.
+/**
+ * cpuset_test_cpumask - test a task's cpus_allowed versus its cpuset's
+ * @tsk: task to test
+ * @scan: struct cgroup_scanner contained in its struct cpuset_hotplug_scanner
+ *
+ * Call with cgroup_mutex held.  May take callback_mutex during call.
+ * Called for each task in a cgroup by cgroup_scan_tasks().
+ * Return nonzero if this tasks's cpus_allowed mask should be changed (in other
+ * words, if its mask is not equal to its cpuset's mask).
+ */
+int cpuset_test_cpumask(struct task_struct *tsk, struct cgroup_scanner *scan)
+{
+       return !cpus_equal(tsk->cpus_allowed,
+                       (cgroup_cs(scan->cg))->cpus_allowed);
+}
+
+/**
+ * cpuset_change_cpumask - make a task's cpus_allowed the same as its cpuset's
+ * @tsk: task to test
+ * @scan: struct cgroup_scanner containing the cgroup of the task
+ *
+ * Called by cgroup_scan_tasks() for each task in a cgroup whose
+ * cpus_allowed mask needs to be changed.
+ *
+ * We don't need to re-check for the cgroup/cpuset membership, since we're
+ * holding cgroup_lock() at this point.
  */
+void cpuset_change_cpumask(struct task_struct *tsk, struct cgroup_scanner *scan)
+{
+       set_cpus_allowed(tsk, (cgroup_cs(scan->cg))->cpus_allowed);
+}
 
+/**
+ * update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it
+ * @cs: the cpuset to consider
+ * @buf: buffer of cpu numbers written to this cpuset
+ */
 static int update_cpumask(struct cpuset *cs, char *buf)
 {
        struct cpuset trialcs;
-       int retval, i;
-       int is_load_balanced;
-       struct cgroup_iter it;
-       struct cgroup *cgrp = cs->css.cgroup;
-       struct task_struct *p, *dropped;
-       /* Never dereference latest_task, since it's not refcounted */
-       struct task_struct *latest_task = NULL;
+       struct cgroup_scanner scan;
        struct ptr_heap heap;
-       struct timespec latest_time = { 0, 0 };
+       int retval;
+       int is_load_balanced;
 
        /* top_cpuset.cpus_allowed tracks cpu_online_map; it's read-only */
        if (cs == &top_cpuset)
@@ -756,7 +752,7 @@ static int update_cpumask(struct cpuset *cs, char *buf)
        trialcs = *cs;
 
        /*
-        * An empty cpus_allowed is ok iff there are no tasks in the cpuset.
+        * An empty cpus_allowed is ok only if the cpuset has no tasks.
         * Since cpulist_parse() fails on an empty mask, we special case
         * that parsing.  The validate_change() call ensures that cpusets
         * with tasks have cpus.
@@ -777,6 +773,7 @@ static int update_cpumask(struct cpuset *cs, char *buf)
        /* Nothing to do if the cpus didn't change */
        if (cpus_equal(cs->cpus_allowed, trialcs.cpus_allowed))
                return 0;
+
        retval = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, &started_after);
        if (retval)
                return retval;
@@ -787,62 +784,19 @@ static int update_cpumask(struct cpuset *cs, char *buf)
        cs->cpus_allowed = trialcs.cpus_allowed;
        mutex_unlock(&callback_mutex);
 
- again:
        /*
         * Scan tasks in the cpuset, and update the cpumasks of any
-        * that need an update. Since we can't call set_cpus_allowed()
-        * while holding tasklist_lock, gather tasks to be processed
-        * in a heap structure. If the statically-sized heap fills up,
-        * overflow tasks that started later, and in future iterations
-        * only consider tasks that started after the latest task in
-        * the previous pass. This guarantees forward progress and
-        * that we don't miss any tasks
+        * that need an update.
         */
-       heap.size = 0;
-       cgroup_iter_start(cgrp, &it);
-       while ((p = cgroup_iter_next(cgrp, &it))) {
-               /* Only affect tasks that don't have the right cpus_allowed */
-               if (cpus_equal(p->cpus_allowed, cs->cpus_allowed))
-                       continue;
-               /*
-                * Only process tasks that started after the last task
-                * we processed
-                */
-               if (!started_after_time(p, &latest_time, latest_task))
-                       continue;
-               dropped = heap_insert(&heap, p);
-               if (dropped == NULL) {
-                       get_task_struct(p);
-               } else if (dropped != p) {
-                       get_task_struct(p);
-                       put_task_struct(dropped);
-               }
-       }
-       cgroup_iter_end(cgrp, &it);
-       if (heap.size) {
-               for (i = 0; i < heap.size; i++) {
-                       struct task_struct *p = heap.ptrs[i];
-                       if (i == 0) {
-                               latest_time = p->start_time;
-                               latest_task = p;
-                       }
-                       set_cpus_allowed(p, cs->cpus_allowed);
-                       put_task_struct(p);
-               }
-               /*
-                * If we had to process any tasks at all, scan again
-                * in case some of them were in the middle of forking
-                * children that didn't notice the new cpumask
-                * restriction.  Not the most efficient way to do it,
-                * but it avoids having to take callback_mutex in the
-                * fork path
-                */
-               goto again;
-       }
+       scan.cg = cs->css.cgroup;
+       scan.test_task = cpuset_test_cpumask;
+       scan.process_task = cpuset_change_cpumask;
+       scan.heap = &heap;
+       cgroup_scan_tasks(&scan);
        heap_free(&heap);
+
        if (is_load_balanced)
                rebuild_sched_domains();
-
        return 0;
 }
 
@@ -854,11 +808,11 @@ static int update_cpumask(struct cpuset *cs, char *buf)
  *    Temporarilly set tasks mems_allowed to target nodes of migration,
  *    so that the migration code can allocate pages on these nodes.
  *
- *    Call holding manage_mutex, so our current->cpuset won't change
- *    during this call, as manage_mutex holds off any attach_task()
+ *    Call holding cgroup_mutex, so current's cpuset won't change
+ *    during this call, as manage_mutex holds off any cpuset_attach()
  *    calls.  Therefore we don't need to take task_lock around the
  *    call to guarantee_online_mems(), as we know no one is changing
- *    our tasks cpuset.
+ *    our task's cpuset.
  *
  *    Hold callback_mutex around the two modifications of our tasks
  *    mems_allowed to synchronize with cpuset_mems_allowed().
@@ -903,7 +857,7 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
  * the cpuset is marked 'memory_migrate', migrate the tasks
  * pages to the new memory.
  *
- * Call with manage_mutex held.  May take callback_mutex during call.
+ * Call with cgroup_mutex held.  May take callback_mutex during call.
  * Will take tasklist_lock, scan tasklist for tasks in cpuset cs,
  * lock each such tasks mm->mmap_sem, scan its vma's and rebind
  * their mempolicies to the cpusets new mems_allowed.
@@ -1016,7 +970,7 @@ static int update_nodemask(struct cpuset *cs, char *buf)
         * tasklist_lock.  Forks can happen again now - the mpol_copy()
         * cpuset_being_rebound check will catch such forks, and rebind
         * their vma mempolicies too.  Because we still hold the global
-        * cpuset manage_mutex, we know that no other rebind effort will
+        * cgroup_mutex, we know that no other rebind effort will
         * be contending for the global variable cpuset_being_rebound.
         * It's ok if we rebind the same mm twice; mpol_rebind_mm()
         * is idempotent.  Also migrate pages in each mm to new nodes.
@@ -1031,7 +985,7 @@ static int update_nodemask(struct cpuset *cs, char *buf)
                mmput(mm);
        }
 
-       /* We're done rebinding vma's to this cpusets new mems_allowed. */
+       /* We're done rebinding vmas to this cpuset's new mems_allowed. */
        kfree(mmarray);
        cpuset_being_rebound = NULL;
        retval = 0;
@@ -1045,7 +999,7 @@ int current_cpuset_is_being_rebound(void)
 }
 
 /*
- * Call with manage_mutex held.
+ * Call with cgroup_mutex held.
  */
 
 static int update_memory_pressure_enabled(struct cpuset *cs, char *buf)
@@ -1066,7 +1020,7 @@ static int update_memory_pressure_enabled(struct cpuset *cs, char *buf)
  * cs: the cpuset to update
  * buf:        the buffer where we read the 0 or 1
  *
- * Call with manage_mutex held.
+ * Call with cgroup_mutex held.
  */
 
 static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
@@ -1200,6 +1154,7 @@ static int fmeter_getrate(struct fmeter *fmp)
        return val;
 }
 
+/* Called by cgroups to determine if a cpuset is usable; cgroup_mutex held */
 static int cpuset_can_attach(struct cgroup_subsys *ss,
                             struct cgroup *cont, struct task_struct *tsk)
 {
@@ -1547,7 +1502,8 @@ static int cpuset_populate(struct cgroup_subsys *ss, struct cgroup *cont)
  * If this becomes a problem for some users who wish to
  * allow that scenario, then cpuset_post_clone() could be
  * changed to grant parent->cpus_allowed-sibling_cpus_exclusive
- * (and likewise for mems) to the new cgroup.
+ * (and likewise for mems) to the new cgroup. Called with cgroup_mutex
+ * held.
  */
 static void cpuset_post_clone(struct cgroup_subsys *ss,
                              struct cgroup *cgroup)
@@ -1571,11 +1527,8 @@ static void cpuset_post_clone(struct cgroup_subsys *ss,
 
 /*
  *     cpuset_create - create a cpuset
- *     parent: cpuset that will be parent of the new cpuset.
- *     name:           name of the new cpuset. Will be strcpy'ed.
- *     mode:           mode to set on new inode
- *
- *     Must be called with the mutex on the parent inode held
+ *     ss:     cpuset cgroup subsystem
+ *     cont:   control group that the new cpuset will be part of
  */
 
 static struct cgroup_subsys_state *cpuset_create(
@@ -1687,53 +1640,140 @@ int __init cpuset_init(void)
        return 0;
 }
 
+/**
+ * cpuset_do_move_task - move a given task to another cpuset
+ * @tsk: pointer to task_struct the task to move
+ * @scan: struct cgroup_scanner contained in its struct cpuset_hotplug_scanner
+ *
+ * Called by cgroup_scan_tasks() for each task in a cgroup.
+ * Return nonzero to stop the walk through the tasks.
+ */
+void cpuset_do_move_task(struct task_struct *tsk, struct cgroup_scanner *scan)
+{
+       struct cpuset_hotplug_scanner *chsp;
+
+       chsp = container_of(scan, struct cpuset_hotplug_scanner, scan);
+       cgroup_attach_task(chsp->to, tsk);
+}
+
+/**
+ * move_member_tasks_to_cpuset - move tasks from one cpuset to another
+ * @from: cpuset in which the tasks currently reside
+ * @to: cpuset to which the tasks will be moved
+ *
+ * Called with cgroup_mutex held
+ * callback_mutex must not be held, as cpuset_attach() will take it.
+ *
+ * The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
+ * calling callback functions for each.
+ */
+static void move_member_tasks_to_cpuset(struct cpuset *from, struct cpuset *to)
+{
+       struct cpuset_hotplug_scanner scan;
+
+       scan.scan.cg = from->css.cgroup;
+       scan.scan.test_task = NULL; /* select all tasks in cgroup */
+       scan.scan.process_task = cpuset_do_move_task;
+       scan.scan.heap = NULL;
+       scan.to = to->css.cgroup;
+
+       if (cgroup_scan_tasks((struct cgroup_scanner *)&scan))
+               printk(KERN_ERR "move_member_tasks_to_cpuset: "
+                               "cgroup_scan_tasks failed\n");
+}
+
 /*
  * If common_cpu_mem_hotplug_unplug(), below, unplugs any CPUs
  * or memory nodes, we need to walk over the cpuset hierarchy,
  * removing that CPU or node from all cpusets.  If this removes the
- * last CPU or node from a cpuset, then the guarantee_online_cpus()
- * or guarantee_online_mems() code will use that emptied cpusets
- * parent online CPUs or nodes.  Cpusets that were already empty of
- * CPUs or nodes are left empty.
+ * last CPU or node from a cpuset, then move the tasks in the empty
+ * cpuset to its next-highest non-empty parent.
  *
- * This routine is intentionally inefficient in a couple of regards.
- * It will check all cpusets in a subtree even if the top cpuset of
- * the subtree has no offline CPUs or nodes.  It checks both CPUs and
- * nodes, even though the caller could have been coded to know that
- * only one of CPUs or nodes needed to be checked on a given call.
- * This was done to minimize text size rather than cpu cycles.
+ * Called with cgroup_mutex held
+ * callback_mutex must not be held, as cpuset_attach() will take it.
+ */
+static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
+{
+       struct cpuset *parent;
+
+       /*
+        * The cgroup's css_sets list is in use if there are tasks
+        * in the cpuset; the list is empty if there are none;
+        * the cs->css.refcnt seems always 0.
+        */
+       if (list_empty(&cs->css.cgroup->css_sets))
+               return;
+
+       /*
+        * Find its next-highest non-empty parent, (top cpuset
+        * has online cpus, so can't be empty).
+        */
+       parent = cs->parent;
+       while (cpus_empty(parent->cpus_allowed) ||
+                       nodes_empty(parent->mems_allowed))
+               parent = parent->parent;
+
+       move_member_tasks_to_cpuset(cs, parent);
+}
+
+/*
+ * Walk the specified cpuset subtree and look for empty cpusets.
+ * The tasks of such cpuset must be moved to a parent cpuset.
+ *
+ * Called with cgroup_mutex held.  We take callback_mutex to modify
+ * cpus_allowed and mems_allowed.
  *
- * Call with both manage_mutex and callback_mutex held.
+ * This walk processes the tree from top to bottom, completing one layer
+ * before dropping down to the next.  It always processes a node before
+ * any of its children.
  *
- * Recursive, on depth of cpuset subtree.
+ * For now, since we lack memory hot unplug, we'll never see a cpuset
+ * that has tasks along with an empty 'mems'.  But if we did see such
+ * a cpuset, we'd handle it just like we do if its 'cpus' was empty.
  */
-
-static void guarantee_online_cpus_mems_in_subtree(const struct cpuset *cur)
+static void scan_for_empty_cpusets(const struct cpuset *root)
 {
+       struct cpuset *cp;      /* scans cpusets being updated */
+       struct cpuset *child;   /* scans child cpusets of cp */
+       struct list_head queue;
        struct cgroup *cont;
-       struct cpuset *c;
 
-       /* Each of our child cpusets mems must be online */
-       list_for_each_entry(cont, &cur->css.cgroup->children, sibling) {
-               c = cgroup_cs(cont);
-               guarantee_online_cpus_mems_in_subtree(c);
-               if (!cpus_empty(c->cpus_allowed))
-                       guarantee_online_cpus(c, &c->cpus_allowed);
-               if (!nodes_empty(c->mems_allowed))
-                       guarantee_online_mems(c, &c->mems_allowed);
+       INIT_LIST_HEAD(&queue);
+
+       list_add_tail((struct list_head *)&root->stack_list, &queue);
+
+       while (!list_empty(&queue)) {
+               cp = container_of(queue.next, struct cpuset, stack_list);
+               list_del(queue.next);
+               list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
+                       child = cgroup_cs(cont);
+                       list_add_tail(&child->stack_list, &queue);
+               }
+               cont = cp->css.cgroup;
+
+               /* Continue past cpusets with all cpus, mems online */
+               if (cpus_subset(cp->cpus_allowed, cpu_online_map) &&
+                   nodes_subset(cp->mems_allowed, node_states[N_HIGH_MEMORY]))
+                       continue;
+
+               /* Remove offline cpus and mems from this cpuset. */
+               mutex_lock(&callback_mutex);
+               cpus_and(cp->cpus_allowed, cp->cpus_allowed, cpu_online_map);
+               nodes_and(cp->mems_allowed, cp->mems_allowed,
+                                               node_states[N_HIGH_MEMORY]);
+               mutex_unlock(&callback_mutex);
+
+               /* Move tasks from the empty cpuset to a parent */
+               if (cpus_empty(cp->cpus_allowed) ||
+                    nodes_empty(cp->mems_allowed))
+                       remove_tasks_in_empty_cpuset(cp);
        }
 }
 
 /*
  * The cpus_allowed and mems_allowed nodemasks in the top_cpuset track
  * cpu_online_map and node_states[N_HIGH_MEMORY].  Force the top cpuset to
- * track what's online after any CPU or memory node hotplug or unplug
- * event.
- *
- * To ensure that we don't remove a CPU or node from the top cpuset
- * that is currently in use by a child cpuset (which would violate
- * the rule that cpusets must be subsets of their parent), we first
- * call the recursive routine guarantee_online_cpus_mems_in_subtree().
+ * track what's online after any CPU or memory node hotplug or unplug event.
  *
  * Since there are two callers of this routine, one for CPU hotplug
  * events and one for memory node hotplug events, we could have coded
@@ -1744,13 +1784,11 @@ static void guarantee_online_cpus_mems_in_subtree(const struct cpuset *cur)
 static void common_cpu_mem_hotplug_unplug(void)
 {
        cgroup_lock();
-       mutex_lock(&callback_mutex);
 
-       guarantee_online_cpus_mems_in_subtree(&top_cpuset);
        top_cpuset.cpus_allowed = cpu_online_map;
        top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
+       scan_for_empty_cpusets(&top_cpuset);
 
-       mutex_unlock(&callback_mutex);
        cgroup_unlock();
 }
 
@@ -1826,7 +1864,7 @@ cpumask_t cpuset_cpus_allowed(struct task_struct *tsk)
 
 /**
  * cpuset_cpus_allowed_locked - return cpus_allowed mask from a tasks cpuset.
- * Must be  called with callback_mutex held.
+ * Must be called with callback_mutex held.
  **/
 cpumask_t cpuset_cpus_allowed_locked(struct task_struct *tsk)
 {
@@ -2163,10 +2201,8 @@ void __cpuset_memory_pressure_bump(void)
  *  - Used for /proc/<pid>/cpuset.
  *  - No need to task_lock(tsk) on this tsk->cpuset reference, as it
  *    doesn't really matter if tsk->cpuset changes after we read it,
- *    and we take manage_mutex, keeping attach_task() from changing it
- *    anyway.  No need to check that tsk->cpuset != NULL, thanks to
- *    the_top_cpuset_hack in cpuset_exit(), which sets an exiting tasks
- *    cpuset to top_cpuset.
+ *    and we take cgroup_mutex, keeping cpuset_attach() from changing it
+ *    anyway.
  */
 static int proc_cpuset_show(struct seq_file *m, void *unused_v)
 {
index 9d3d0f0b27d9a6165384d6af55013488aacfdc72..eb9934a82fc1a900f29eb751e520603b82f2492f 100644 (file)
@@ -1590,8 +1590,6 @@ repeat:
                                        goto repeat;
                                if (retval != 0) /* He released the lock.  */
                                        goto end;
-                       } else if (p->exit_state == EXIT_DEAD) {
-                               continue;
                        } else if (p->exit_state == EXIT_ZOMBIE) {
                                /*
                                 * Eligible but we cannot release it yet:
@@ -1606,7 +1604,7 @@ repeat:
                                /* He released the lock.  */
                                if (retval != 0)
                                        goto end;
-                       } else {
+                       } else if (p->exit_state != EXIT_DEAD) {
 check_continued:
                                /*
                                 * It's running now, so it might later
index 2b55b74cd99999f1eccdedc2158d29945ab16d98..b2ef8e4fad70da87632b315f3be76f829371c99b 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/ptrace.h>
 #include <linux/mount.h>
 #include <linux/audit.h>
+#include <linux/memcontrol.h>
 #include <linux/profile.h>
 #include <linux/rmap.h>
 #include <linux/acct.h>
@@ -340,7 +341,7 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(mmlist_lock);
 
 #include <linux/init_task.h>
 
-static struct mm_struct * mm_init(struct mm_struct * mm)
+static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
 {
        atomic_set(&mm->mm_users, 1);
        atomic_set(&mm->mm_count, 1);
@@ -357,11 +358,14 @@ static struct mm_struct * mm_init(struct mm_struct * mm)
        mm->ioctx_list = NULL;
        mm->free_area_cache = TASK_UNMAPPED_BASE;
        mm->cached_hole_size = ~0UL;
+       mm_init_cgroup(mm, p);
 
        if (likely(!mm_alloc_pgd(mm))) {
                mm->def_flags = 0;
                return mm;
        }
+
+       mm_free_cgroup(mm);
        free_mm(mm);
        return NULL;
 }
@@ -376,7 +380,7 @@ struct mm_struct * mm_alloc(void)
        mm = allocate_mm();
        if (mm) {
                memset(mm, 0, sizeof(*mm));
-               mm = mm_init(mm);
+               mm = mm_init(mm, current);
        }
        return mm;
 }
@@ -390,6 +394,7 @@ void fastcall __mmdrop(struct mm_struct *mm)
 {
        BUG_ON(mm == &init_mm);
        mm_free_pgd(mm);
+       mm_free_cgroup(mm);
        destroy_context(mm);
        free_mm(mm);
 }
@@ -511,7 +516,7 @@ static struct mm_struct *dup_mm(struct task_struct *tsk)
        mm->token_priority = 0;
        mm->last_interval = 0;
 
-       if (!mm_init(mm))
+       if (!mm_init(mm, tsk))
                goto fail_nomem;
 
        if (init_new_context(tsk, mm))
@@ -1399,7 +1404,7 @@ fork_out:
        return ERR_PTR(retval);
 }
 
-noinline struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_regs *regs)
+noinline struct pt_regs * __cpuinit __attribute__((weak)) idle_regs(struct pt_regs *regs)
 {
        memset(regs, 0, sizeof(struct pt_regs));
        return regs;
@@ -1510,7 +1515,7 @@ long do_fork(unsigned long clone_flags,
                if (!(clone_flags & CLONE_STOPPED))
                        wake_up_new_task(p, clone_flags);
                else
-                       p->state = TASK_STOPPED;
+                       __set_task_state(p, TASK_STOPPED);
 
                if (unlikely (trace)) {
                        current->ptrace_message = nr;
index 7dadc71ce5162926529172e5a9ff71b86590a4a4..f091d13def0083b8d25107993affa1065cb8aabc 100644 (file)
@@ -53,14 +53,6 @@ static inline int is_kernel_inittext(unsigned long addr)
        return 0;
 }
 
-static inline int is_kernel_extratext(unsigned long addr)
-{
-       if (addr >= (unsigned long)_sextratext
-           && addr <= (unsigned long)_eextratext)
-               return 1;
-       return 0;
-}
-
 static inline int is_kernel_text(unsigned long addr)
 {
        if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)
@@ -80,8 +72,7 @@ static int is_ksym_addr(unsigned long addr)
        if (all_var)
                return is_kernel(addr);
 
-       return is_kernel_text(addr) || is_kernel_inittext(addr) ||
-               is_kernel_extratext(addr);
+       return is_kernel_text(addr) || is_kernel_inittext(addr);
 }
 
 /* expand a compressed symbol data into the resulting uncompressed string,
index 9a26eec9eb04b858cfb7d3244071b94f4d4872c9..06a0e27756516e047e5df59b91d4b4fc8d81753f 100644 (file)
@@ -1361,8 +1361,8 @@ unsigned long __attribute__ ((weak)) paddr_vmcoreinfo_note(void)
 
 static int __init crash_save_vmcoreinfo_init(void)
 {
-       vmcoreinfo_append_str("OSRELEASE=%s\n", init_uts_ns.name.release);
-       vmcoreinfo_append_str("PAGESIZE=%ld\n", PAGE_SIZE);
+       VMCOREINFO_OSRELEASE(init_uts_ns.name.release);
+       VMCOREINFO_PAGESIZE(PAGE_SIZE);
 
        VMCOREINFO_SYMBOL(init_uts_ns);
        VMCOREINFO_SYMBOL(node_online_map);
@@ -1376,15 +1376,15 @@ static int __init crash_save_vmcoreinfo_init(void)
 #ifdef CONFIG_SPARSEMEM
        VMCOREINFO_SYMBOL(mem_section);
        VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS);
-       VMCOREINFO_SIZE(mem_section);
+       VMCOREINFO_STRUCT_SIZE(mem_section);
        VMCOREINFO_OFFSET(mem_section, section_mem_map);
 #endif
-       VMCOREINFO_SIZE(page);
-       VMCOREINFO_SIZE(pglist_data);
-       VMCOREINFO_SIZE(zone);
-       VMCOREINFO_SIZE(free_area);
-       VMCOREINFO_SIZE(list_head);
-       VMCOREINFO_TYPEDEF_SIZE(nodemask_t);
+       VMCOREINFO_STRUCT_SIZE(page);
+       VMCOREINFO_STRUCT_SIZE(pglist_data);
+       VMCOREINFO_STRUCT_SIZE(zone);
+       VMCOREINFO_STRUCT_SIZE(free_area);
+       VMCOREINFO_STRUCT_SIZE(list_head);
+       VMCOREINFO_SIZE(nodemask_t);
        VMCOREINFO_OFFSET(page, flags);
        VMCOREINFO_OFFSET(page, _count);
        VMCOREINFO_OFFSET(page, mapping);
index d0493eafea3ec5d86ece12d8861421b6bea13ec7..7a86e64323385785bda6e838f01c9637e192844a 100644 (file)
@@ -699,6 +699,12 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p,
                                 struct kretprobe_instance, uflist);
                ri->rp = rp;
                ri->task = current;
+
+               if (rp->entry_handler && rp->entry_handler(ri, regs)) {
+                       spin_unlock_irqrestore(&kretprobe_lock, flags);
+                       return 0;
+               }
+
                arch_prepare_kretprobe(ri, regs);
 
                /* XXX(hch): why is there no hlist_move_head? */
@@ -745,7 +751,8 @@ int __kprobes register_kretprobe(struct kretprobe *rp)
        INIT_HLIST_HEAD(&rp->used_instances);
        INIT_HLIST_HEAD(&rp->free_instances);
        for (i = 0; i < rp->maxactive; i++) {
-               inst = kmalloc(sizeof(struct kretprobe_instance), GFP_KERNEL);
+               inst = kmalloc(sizeof(struct kretprobe_instance) +
+                              rp->data_size, GFP_KERNEL);
                if (inst == NULL) {
                        free_rp_inst(rp);
                        return -ENOMEM;
index 4253f472f0606cc419eacf952cc9b801a0441ef9..643360d1bb144fda223301b348059cd5381eb35e 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/notifier.h>
 #include <linux/rcupdate.h>
 #include <linux/vmalloc.h>
+#include <linux/reboot.h>
 
 /*
  *     Notifier list for kernel code which wants to be called
index 42fe5e6126c0948e5b6859f5fcc75ebb71e2b039..e28c70628bb7d1cd723c84b26cbfeb1a6104c2a4 100644 (file)
@@ -272,7 +272,7 @@ static int param_array(const char *name,
                       unsigned int min, unsigned int max,
                       void *elem, int elemsize,
                       int (*set)(const char *, struct kernel_param *kp),
-                      int *num)
+                      unsigned int *num)
 {
        int ret;
        struct kernel_param kp;
index f815455431bff3c95855a674086e6c1d8322a7c4..3b30bccdfcdc92def5dcb4313d4606bc58d6cb46 100644 (file)
@@ -368,6 +368,7 @@ struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type)
        }
        return result;
 }
+EXPORT_SYMBOL(pid_task);
 
 /*
  * Must be called under rcu_read_lock() or with tasklist_lock read-held.
index 29ae1e99cde08b247aa106a2939496abf3b3c871..4a090621f3793fe705352565a41a022441e617b6 100644 (file)
@@ -93,16 +93,16 @@ static int console_locked, console_suspended;
  */
 static DEFINE_SPINLOCK(logbuf_lock);
 
-#define LOG_BUF_MASK   (log_buf_len-1)
+#define LOG_BUF_MASK (log_buf_len-1)
 #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
 
 /*
  * The indices into log_buf are not constrained to log_buf_len - they
  * must be masked before subscripting
  */
-static unsigned long log_start;        /* Index into log_buf: next char to be read by syslog() */
-static unsigned long con_start;        /* Index into log_buf: next char to be sent to consoles */
-static unsigned long log_end;  /* Index into log_buf: most-recently-written-char + 1 */
+static unsigned log_start;     /* Index into log_buf: next char to be read by syslog() */
+static unsigned con_start;     /* Index into log_buf: next char to be sent to consoles */
+static unsigned log_end;       /* Index into log_buf: most-recently-written-char + 1 */
 
 /*
  *     Array of consoles built from command line options (console=)
@@ -128,17 +128,17 @@ static int console_may_schedule;
 static char __log_buf[__LOG_BUF_LEN];
 static char *log_buf = __log_buf;
 static int log_buf_len = __LOG_BUF_LEN;
-static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
+static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
 
 static int __init log_buf_len_setup(char *str)
 {
-       unsigned long size = memparse(str, &str);
+       unsigned size = memparse(str, &str);
        unsigned long flags;
 
        if (size)
                size = roundup_pow_of_two(size);
        if (size > log_buf_len) {
-               unsigned long start, dest_idx, offset;
+               unsigned start, dest_idx, offset;
                char *new_log_buf;
 
                new_log_buf = alloc_bootmem(size);
@@ -295,7 +295,7 @@ int log_buf_read(int idx)
  */
 int do_syslog(int type, char __user *buf, int len)
 {
-       unsigned long i, j, limit, count;
+       unsigned i, j, limit, count;
        int do_clear = 0;
        char c;
        int error = 0;
@@ -436,7 +436,7 @@ asmlinkage long sys_syslog(int type, char __user *buf, int len)
 /*
  * Call the console drivers on a range of log_buf
  */
-static void __call_console_drivers(unsigned long start, unsigned long end)
+static void __call_console_drivers(unsigned start, unsigned end)
 {
        struct console *con;
 
@@ -463,8 +463,8 @@ early_param("ignore_loglevel", ignore_loglevel_setup);
 /*
  * Write out chars from start to end - 1 inclusive
  */
-static void _call_console_drivers(unsigned long start,
-                               unsigned long end, int msg_log_level)
+static void _call_console_drivers(unsigned start,
+                               unsigned end, int msg_log_level)
 {
        if ((msg_log_level < console_loglevel || ignore_loglevel) &&
                        console_drivers && start != end) {
@@ -484,12 +484,12 @@ static void _call_console_drivers(unsigned long start,
  * log_buf[start] to log_buf[end - 1].
  * The console_sem must be held.
  */
-static void call_console_drivers(unsigned long start, unsigned long end)
+static void call_console_drivers(unsigned start, unsigned end)
 {
-       unsigned long cur_index, start_print;
+       unsigned cur_index, start_print;
        static int msg_level = -1;
 
-       BUG_ON(((long)(start - end)) > 0);
+       BUG_ON(((int)(start - end)) > 0);
 
        cur_index = start;
        start_print = start;
@@ -790,7 +790,7 @@ asmlinkage long sys_syslog(int type, char __user *buf, int len)
        return -ENOSYS;
 }
 
-static void call_console_drivers(unsigned long start, unsigned long end)
+static void call_console_drivers(unsigned start, unsigned end)
 {
 }
 
@@ -983,8 +983,8 @@ void wake_up_klogd(void)
 void release_console_sem(void)
 {
        unsigned long flags;
-       unsigned long _con_start, _log_end;
-       unsigned long wake_klogd = 0;
+       unsigned _con_start, _log_end;
+       unsigned wake_klogd = 0;
 
        if (console_suspended) {
                up(&secondary_console_sem);
@@ -1275,7 +1275,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
 int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
 {
        static DEFINE_SPINLOCK(ratelimit_lock);
-       static unsigned long toks = 10 * 5 * HZ;
+       static unsigned toks = 10 * 5 * HZ;
        static unsigned long last_msg;
        static int missed;
        unsigned long flags;
index b0d4ab4dfd3d27ee60e3a044f9e0bc3bba665d88..628b03ab88a579c52f9c802440e768c4752ab957 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/signal.h>
 #include <linux/audit.h>
 #include <linux/pid_namespace.h>
+#include <linux/syscalls.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -53,7 +54,7 @@ void ptrace_untrace(struct task_struct *child)
        spin_lock(&child->sighand->siglock);
        if (task_is_traced(child)) {
                if (child->signal->flags & SIGNAL_STOP_STOPPED) {
-                       child->state = TASK_STOPPED;
+                       __set_task_state(child, TASK_STOPPED);
                } else {
                        signal_wake_up(child, 1);
                }
@@ -103,18 +104,16 @@ int ptrace_check_attach(struct task_struct *child, int kill)
            && child->signal != NULL) {
                ret = 0;
                spin_lock_irq(&child->sighand->siglock);
-               if (task_is_stopped(child)) {
+               if (task_is_stopped(child))
                        child->state = TASK_TRACED;
-               } else if (!task_is_traced(child) && !kill) {
+               else if (!task_is_traced(child) && !kill)
                        ret = -ESRCH;
-               }
                spin_unlock_irq(&child->sighand->siglock);
        }
        read_unlock(&tasklist_lock);
 
-       if (!ret && !kill) {
+       if (!ret && !kill)
                wait_task_inactive(child);
-       }
 
        /* All systems go.. */
        return ret;
index 7c0373322f18892eea75e3773714554f59f46c1e..d080b9d161a75eee95bbf6d7aed235354bda9e9c 100644 (file)
@@ -37,37 +37,31 @@ static void relay_file_mmap_close(struct vm_area_struct *vma)
 }
 
 /*
- * nopage() vm_op implementation for relay file mapping.
+ * fault() vm_op implementation for relay file mapping.
  */
-static struct page *relay_buf_nopage(struct vm_area_struct *vma,
-                                    unsigned long address,
-                                    int *type)
+static int relay_buf_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct page *page;
        struct rchan_buf *buf = vma->vm_private_data;
-       unsigned long offset = address - vma->vm_start;
+       pgoff_t pgoff = vmf->pgoff;
 
-       if (address > vma->vm_end)
-               return NOPAGE_SIGBUS; /* Disallow mremap */
        if (!buf)
-               return NOPAGE_OOM;
+               return VM_FAULT_OOM;
 
-       page = vmalloc_to_page(buf->start + offset);
+       page = vmalloc_to_page(buf->start + (pgoff << PAGE_SHIFT));
        if (!page)
-               return NOPAGE_OOM;
+               return VM_FAULT_SIGBUS;
        get_page(page);
+       vmf->page = page;
 
-       if (type)
-               *type = VM_FAULT_MINOR;
-
-       return page;
+       return 0;
 }
 
 /*
  * vm_ops for relay file mappings.
  */
 static struct vm_operations_struct relay_file_mmap_ops = {
-       .nopage = relay_buf_nopage,
+       .fault = relay_buf_fault,
        .close = relay_file_mmap_close,
 };
 
diff --git a/kernel/res_counter.c b/kernel/res_counter.c
new file mode 100644 (file)
index 0000000..16cbec2
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * resource cgroups
+ *
+ * Copyright 2007 OpenVZ SWsoft Inc
+ *
+ * Author: Pavel Emelianov <xemul@openvz.org>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/parser.h>
+#include <linux/fs.h>
+#include <linux/res_counter.h>
+#include <linux/uaccess.h>
+
+void res_counter_init(struct res_counter *counter)
+{
+       spin_lock_init(&counter->lock);
+       counter->limit = (unsigned long long)LLONG_MAX;
+}
+
+int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
+{
+       if (counter->usage + val > counter->limit) {
+               counter->failcnt++;
+               return -ENOMEM;
+       }
+
+       counter->usage += val;
+       return 0;
+}
+
+int res_counter_charge(struct res_counter *counter, unsigned long val)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&counter->lock, flags);
+       ret = res_counter_charge_locked(counter, val);
+       spin_unlock_irqrestore(&counter->lock, flags);
+       return ret;
+}
+
+void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
+{
+       if (WARN_ON(counter->usage < val))
+               val = counter->usage;
+
+       counter->usage -= val;
+}
+
+void res_counter_uncharge(struct res_counter *counter, unsigned long val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&counter->lock, flags);
+       res_counter_uncharge_locked(counter, val);
+       spin_unlock_irqrestore(&counter->lock, flags);
+}
+
+
+static inline unsigned long long *
+res_counter_member(struct res_counter *counter, int member)
+{
+       switch (member) {
+       case RES_USAGE:
+               return &counter->usage;
+       case RES_LIMIT:
+               return &counter->limit;
+       case RES_FAILCNT:
+               return &counter->failcnt;
+       };
+
+       BUG();
+       return NULL;
+}
+
+ssize_t res_counter_read(struct res_counter *counter, int member,
+               const char __user *userbuf, size_t nbytes, loff_t *pos,
+               int (*read_strategy)(unsigned long long val, char *st_buf))
+{
+       unsigned long long *val;
+       char buf[64], *s;
+
+       s = buf;
+       val = res_counter_member(counter, member);
+       if (read_strategy)
+               s += read_strategy(*val, s);
+       else
+               s += sprintf(s, "%llu\n", *val);
+       return simple_read_from_buffer((void __user *)userbuf, nbytes,
+                       pos, buf, s - buf);
+}
+
+ssize_t res_counter_write(struct res_counter *counter, int member,
+               const char __user *userbuf, size_t nbytes, loff_t *pos,
+               int (*write_strategy)(char *st_buf, unsigned long long *val))
+{
+       int ret;
+       char *buf, *end;
+       unsigned long flags;
+       unsigned long long tmp, *val;
+
+       buf = kmalloc(nbytes + 1, GFP_KERNEL);
+       ret = -ENOMEM;
+       if (buf == NULL)
+               goto out;
+
+       buf[nbytes] = '\0';
+       ret = -EFAULT;
+       if (copy_from_user(buf, userbuf, nbytes))
+               goto out_free;
+
+       ret = -EINVAL;
+
+       if (write_strategy) {
+               if (write_strategy(buf, &tmp)) {
+                       goto out_free;
+               }
+       } else {
+               tmp = simple_strtoull(buf, &end, 10);
+               if (*end != '\0')
+                       goto out_free;
+       }
+       spin_lock_irqsave(&counter->lock, flags);
+       val = res_counter_member(counter, member);
+       *val = tmp;
+       spin_unlock_irqrestore(&counter->lock, flags);
+       ret = nbytes;
+out_free:
+       kfree(buf);
+out:
+       return ret;
+}
index 6a5f97cd337a3bc980428ea1c186efedbe991a25..5d30ff5618475273c60e6aeb59e7cf092603b9a4 100644 (file)
@@ -1577,6 +1577,17 @@ static inline int may_ptrace_stop(void)
        return 1;
 }
 
+/*
+ * Return nonzero if there is a SIGKILL that should be waking us up.
+ * Called with the siglock held.
+ */
+static int sigkill_pending(struct task_struct *tsk)
+{
+       return ((sigismember(&tsk->pending.signal, SIGKILL) ||
+                sigismember(&tsk->signal->shared_pending.signal, SIGKILL)) &&
+               !unlikely(sigismember(&tsk->blocked, SIGKILL)));
+}
+
 /*
  * This must be called with current->sighand->siglock held.
  *
@@ -1590,6 +1601,26 @@ static inline int may_ptrace_stop(void)
  */
 static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
 {
+       int killed = 0;
+
+       if (arch_ptrace_stop_needed(exit_code, info)) {
+               /*
+                * The arch code has something special to do before a
+                * ptrace stop.  This is allowed to block, e.g. for faults
+                * on user stack pages.  We can't keep the siglock while
+                * calling arch_ptrace_stop, so we must release it now.
+                * To preserve proper semantics, we must do this before
+                * any signal bookkeeping like checking group_stop_count.
+                * Meanwhile, a SIGKILL could come in before we retake the
+                * siglock.  That must prevent us from sleeping in TASK_TRACED.
+                * So after regaining the lock, we must check for SIGKILL.
+                */
+               spin_unlock_irq(&current->sighand->siglock);
+               arch_ptrace_stop(exit_code, info);
+               spin_lock_irq(&current->sighand->siglock);
+               killed = sigkill_pending(current);
+       }
+
        /*
         * If there is a group stop in progress,
         * we must participate in the bookkeeping.
@@ -1601,11 +1632,11 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
        current->exit_code = exit_code;
 
        /* Let the debugger run.  */
-       set_current_state(TASK_TRACED);
+       __set_current_state(TASK_TRACED);
        spin_unlock_irq(&current->sighand->siglock);
        try_to_freeze();
        read_lock(&tasklist_lock);
-       if (may_ptrace_stop()) {
+       if (!unlikely(killed) && may_ptrace_stop()) {
                do_notify_parent_cldstop(current, CLD_TRAPPED);
                read_unlock(&tasklist_lock);
                schedule();
index 3507cabe963bd453857b68f6bf56b59103d0781d..b0aeeaf22ce49c8c76098aac5224b1f4c44d4c4d 100644 (file)
@@ -74,7 +74,7 @@ static int srcu_readers_active_idx(struct srcu_struct *sp, int idx)
  * severe errors when invoked on an active srcu_struct.  That said, it
  * can be useful as an error check at cleanup time.
  */
-int srcu_readers_active(struct srcu_struct *sp)
+static int srcu_readers_active(struct srcu_struct *sp)
 {
        return srcu_readers_active_idx(sp, 0) + srcu_readers_active_idx(sp, 1);
 }
@@ -255,4 +255,3 @@ EXPORT_SYMBOL_GPL(srcu_read_lock);
 EXPORT_SYMBOL_GPL(srcu_read_unlock);
 EXPORT_SYMBOL_GPL(synchronize_srcu);
 EXPORT_SYMBOL_GPL(srcu_batches_completed);
-EXPORT_SYMBOL_GPL(srcu_readers_active);
index 51b5ee53571a63558cef49075de15c4dc25396a6..6f4e0e13f70c337c531be43b0d3cc5296c972c71 100644 (file)
@@ -29,7 +29,6 @@ enum stopmachine_state {
 static enum stopmachine_state stopmachine_state;
 static unsigned int stopmachine_num_threads;
 static atomic_t stopmachine_thread_ack;
-static DECLARE_MUTEX(stopmachine_mutex);
 
 static int stopmachine(void *cpu)
 {
@@ -170,6 +169,7 @@ static int do_stop(void *_smdata)
 struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
                                       unsigned int cpu)
 {
+       static DEFINE_MUTEX(stopmachine_mutex);
        struct stop_machine_data smdata;
        struct task_struct *p;
 
@@ -177,7 +177,7 @@ struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
        smdata.data = data;
        init_completion(&smdata.done);
 
-       down(&stopmachine_mutex);
+       mutex_lock(&stopmachine_mutex);
 
        /* If they don't care which CPU fn runs on, bind to any online one. */
        if (cpu == NR_CPUS)
@@ -193,7 +193,7 @@ struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
                wake_up_process(p);
                wait_for_completion(&smdata.done);
        }
-       up(&stopmachine_mutex);
+       mutex_unlock(&stopmachine_mutex);
        return p;
 }
 
index 53de35fc82458eeade26a07e9a36f1acfc18b88a..e3c08d4324deed268673c23ff8efd01817874d68 100644 (file)
@@ -1145,16 +1145,16 @@ static int groups_to_user(gid_t __user *grouplist,
     struct group_info *group_info)
 {
        int i;
-       int count = group_info->ngroups;
+       unsigned int count = group_info->ngroups;
 
        for (i = 0; i < group_info->nblocks; i++) {
-               int cp_count = min(NGROUPS_PER_BLOCK, count);
-               int off = i * NGROUPS_PER_BLOCK;
-               int len = cp_count * sizeof(*grouplist);
+               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
+               unsigned int len = cp_count * sizeof(*grouplist);
 
-               if (copy_to_user(grouplist+off, group_info->blocks[i], len))
+               if (copy_to_user(grouplist, group_info->blocks[i], len))
                        return -EFAULT;
 
+               grouplist += NGROUPS_PER_BLOCK;
                count -= cp_count;
        }
        return 0;
@@ -1165,16 +1165,16 @@ static int groups_from_user(struct group_info *group_info,
     gid_t __user *grouplist)
 {
        int i;
-       int count = group_info->ngroups;
+       unsigned int count = group_info->ngroups;
 
        for (i = 0; i < group_info->nblocks; i++) {
-               int cp_count = min(NGROUPS_PER_BLOCK, count);
-               int off = i * NGROUPS_PER_BLOCK;
-               int len = cp_count * sizeof(*grouplist);
+               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
+               unsigned int len = cp_count * sizeof(*grouplist);
 
-               if (copy_from_user(group_info->blocks[i], grouplist+off, len))
+               if (copy_from_user(group_info->blocks[i], grouplist, len))
                        return -EFAULT;
 
+               grouplist += NGROUPS_PER_BLOCK;
                count -= cp_count;
        }
        return 0;
@@ -1472,7 +1472,7 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
        if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
            !capable(CAP_SYS_RESOURCE))
                return -EPERM;
-       if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN)
+       if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
                return -EPERM;
 
        retval = security_task_setrlimit(resource, &new_rlim);
index 5e2ad5bf88e280fdbc83b61a380909555e121a71..8c98d8147d883ac977d08ff8189b7fd4c1042136 100644 (file)
@@ -67,6 +67,7 @@ extern int sysctl_overcommit_memory;
 extern int sysctl_overcommit_ratio;
 extern int sysctl_panic_on_oom;
 extern int sysctl_oom_kill_allocating_task;
+extern int sysctl_oom_dump_tasks;
 extern int max_threads;
 extern int core_uses_pid;
 extern int suid_dumpable;
@@ -870,6 +871,14 @@ static struct ctl_table vm_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "oom_dump_tasks",
+               .data           = &sysctl_oom_dump_tasks,
+               .maxlen         = sizeof(sysctl_oom_dump_tasks),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
        {
                .ctl_name       = VM_OVERCOMMIT_RATIO,
                .procname       = "overcommit_ratio",
@@ -1202,6 +1211,14 @@ static struct ctl_table fs_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "nr_open",
+               .data           = &sysctl_nr_open,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
        {
                .ctl_name       = FS_DENTRY,
                .procname       = "dentry-state",
index 88cdb109e13cbf605049ef3955054fd5774660ee..06b6395b45b25dcde1a2dd3e1075bce406742ba4 100644 (file)
@@ -135,6 +135,12 @@ static int test_jprobe(void)
 #ifdef CONFIG_KRETPROBES
 static u32 krph_val;
 
+static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       krph_val = (rand1 / div_factor);
+       return 0;
+}
+
 static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        unsigned long ret = regs_return_value(regs);
@@ -144,13 +150,19 @@ static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
                printk(KERN_ERR "Kprobe smoke test failed: "
                                "incorrect value in kretprobe handler\n");
        }
+       if (krph_val == 0) {
+               handler_errors++;
+               printk(KERN_ERR "Kprobe smoke test failed: "
+                               "call to kretprobe entry handler failed\n");
+       }
 
-       krph_val = (rand1 / div_factor);
+       krph_val = rand1;
        return 0;
 }
 
 static struct kretprobe rp = {
        .handler        = return_handler,
+       .entry_handler  = entry_handler,
        .kp.symbol_name = "kprobe_target"
 };
 
@@ -167,7 +179,7 @@ static int test_kretprobe(void)
 
        ret = kprobe_target(rand1);
        unregister_kretprobe(&rp);
-       if (krph_val == 0) {
+       if (krph_val != rand1) {
                printk(KERN_ERR "Kprobe smoke test failed: "
                                "kretprobe handler not called\n");
                handler_errors++;
index 4064c0566e77db73c9cd3b5534884975dc4394e0..33af3e55570dfc5d8fe74aba067d2e26591c1a91 100644 (file)
@@ -566,7 +566,11 @@ EXPORT_SYMBOL(jiffies_to_timeval);
 clock_t jiffies_to_clock_t(long x)
 {
 #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
+# if HZ < USER_HZ
+       return x * (USER_HZ / HZ);
+# else
        return x / (HZ / USER_HZ);
+# endif
 #else
        u64 tmp = (u64)x * TICK_NSEC;
        do_div(tmp, (NSEC_PER_SEC / USER_HZ));
@@ -599,7 +603,14 @@ EXPORT_SYMBOL(clock_t_to_jiffies);
 u64 jiffies_64_to_clock_t(u64 x)
 {
 #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
+# if HZ < USER_HZ
+       x *= USER_HZ;
+       do_div(x, HZ);
+# elif HZ > USER_HZ
        do_div(x, HZ / USER_HZ);
+# else
+       /* Nothing to do */
+# endif
 #else
        /*
         * There are better ways that don't overflow early,
@@ -611,7 +622,6 @@ u64 jiffies_64_to_clock_t(u64 x)
 #endif
        return x;
 }
-
 EXPORT_SYMBOL(jiffies_64_to_clock_t);
 
 u64 nsec_to_clock_t(u64 x)
@@ -646,7 +656,6 @@ u64 get_jiffies_64(void)
        } while (read_seqretry(&xtime_lock, seq));
        return ret;
 }
-
 EXPORT_SYMBOL(get_jiffies_64);
 #endif
 
index 6e9259a5d5010ac7e869f4f567fd3c0618002943..81afb3927eccca2a8f684eb41508740779ed102a 100644 (file)
@@ -363,15 +363,13 @@ void clocksource_unregister(struct clocksource *cs)
 static ssize_t
 sysfs_show_current_clocksources(struct sys_device *dev, char *buf)
 {
-       char *curr = buf;
+       ssize_t count = 0;
 
        spin_lock_irq(&clocksource_lock);
-       curr += sprintf(curr, "%s ", curr_clocksource->name);
+       count = snprintf(buf, PAGE_SIZE, "%s\n", curr_clocksource->name);
        spin_unlock_irq(&clocksource_lock);
 
-       curr += sprintf(curr, "\n");
-
-       return curr - buf;
+       return count;
 }
 
 /**
@@ -439,17 +437,20 @@ static ssize_t
 sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
 {
        struct clocksource *src;
-       char *curr = buf;
+       ssize_t count = 0;
 
        spin_lock_irq(&clocksource_lock);
        list_for_each_entry(src, &clocksource_list, list) {
-               curr += sprintf(curr, "%s ", src->name);
+               count += snprintf(buf + count,
+                                 max((ssize_t)PAGE_SIZE - count, (ssize_t)0),
+                                 "%s ", src->name);
        }
        spin_unlock_irq(&clocksource_lock);
 
-       curr += sprintf(curr, "\n");
+       count += snprintf(buf + count,
+                         max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "\n");
 
-       return curr - buf;
+       return count;
 }
 
 /*
index 9fbb472b8cf0a4e3016480fb205c42eda38dabf8..70b29b59343f6e5a0a0e2cd8cf636748ed16925d 100644 (file)
@@ -818,12 +818,14 @@ unsigned long next_timer_interrupt(void)
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
 void account_process_tick(struct task_struct *p, int user_tick)
 {
+       cputime_t one_jiffy = jiffies_to_cputime(1);
+
        if (user_tick) {
-               account_user_time(p, jiffies_to_cputime(1));
-               account_user_time_scaled(p, jiffies_to_cputime(1));
+               account_user_time(p, one_jiffy);
+               account_user_time_scaled(p, cputime_to_scaled(one_jiffy));
        } else {
-               account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1));
-               account_system_time_scaled(p, jiffies_to_cputime(1));
+               account_system_time(p, HARDIRQ_OFFSET, one_jiffy);
+               account_system_time_scaled(p, cputime_to_scaled(one_jiffy));
        }
 }
 #endif
index 463f4560f16da1e6d03394b46d8e0763948501f7..179c0874559569bf2626cbfc70bfcfef09474097 100644 (file)
@@ -57,10 +57,10 @@ search_extable(const struct exception_table_entry *first,
        while (first <= last) {
                const struct exception_table_entry *mid;
 
-               mid = (last - first) / 2 + first;
+               mid = ((last - first) >> 1) + first;
                /*
-                * careful, the distance between entries can be
-                * larger than 2GB:
+                * careful, the distance between value and insn
+                * can be larger than MAX_LONG:
                 */
                if (mid->insn < value)
                        first = mid + 1;
index eddc9b3d38762ed17b06da35f26450f34c9ffd1a..6c90fb90e19c2ec25571947b7b98f88262e23ba4 100644 (file)
@@ -42,7 +42,9 @@ unsigned int debug_smp_processor_id(void)
        if (!printk_ratelimit())
                goto out_enable;
 
-       printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] code: %s/%d\n", preempt_count(), current->comm, current->pid);
+       printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] "
+                       "code: %s/%d\n",
+                       preempt_count() - 1, current->comm, current->pid);
        print_symbol("caller is %s\n", (long)__builtin_return_address(0));
        dump_stack();
 
index 4af5dff372779949a28244208c26253e3356f60a..9f117bab5322e59b49cba45146b0e54176d206ca 100644 (file)
@@ -32,4 +32,5 @@ obj-$(CONFIG_FS_XIP) += filemap_xip.o
 obj-$(CONFIG_MIGRATION) += migrate.o
 obj-$(CONFIG_SMP) += allocpercpu.o
 obj-$(CONFIG_QUICKLIST) += quicklist.o
+obj-$(CONFIG_CGROUP_MEM_CONT) += memcontrol.o
 
index 00b02623f008e924856329770c68ad0d3c3d7917..7e58322b7134ff1d04e40269e030bdd53e1c87f6 100644 (file)
@@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(__percpu_populate_mask);
  */
 void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask)
 {
-       void *pdata = kzalloc(sizeof(struct percpu_data), gfp);
+       void *pdata = kzalloc(nr_cpu_ids * sizeof(void *), gfp);
        void *__pdata = __percpu_disguise(pdata);
 
        if (unlikely(!pdata))
index 00a96970b237efe9a62c8c6cd8859ef625868bc1..f6ff4337b4242e911ab4e4faadb160b76a445b50 100644 (file)
@@ -111,11 +111,12 @@ static unsigned long __init init_bootmem_core(pg_data_t *pgdat,
  * might be used for boot-time allocations - or it might get added
  * to the free page pool later on.
  */
-static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
-                                       unsigned long size)
+static int __init reserve_bootmem_core(bootmem_data_t *bdata,
+                       unsigned long addr, unsigned long size, int flags)
 {
        unsigned long sidx, eidx;
        unsigned long i;
+       int ret;
 
        /*
         * round up, partially reserved pages are considered
@@ -133,7 +134,20 @@ static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long add
 #ifdef CONFIG_DEBUG_BOOTMEM
                        printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
 #endif
+                       if (flags & BOOTMEM_EXCLUSIVE) {
+                               ret = -EBUSY;
+                               goto err;
+                       }
                }
+
+       return 0;
+
+err:
+       /* unreserve memory we accidentally reserved */
+       for (i--; i >= sidx; i--)
+               clear_bit(i, bdata->node_bootmem_map);
+
+       return ret;
 }
 
 static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
@@ -374,9 +388,9 @@ unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,
 }
 
 void __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
-                                unsigned long size)
+                                unsigned long size, int flags)
 {
-       reserve_bootmem_core(pgdat->bdata, physaddr, size);
+       reserve_bootmem_core(pgdat->bdata, physaddr, size, flags);
 }
 
 void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
@@ -398,9 +412,10 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
 }
 
 #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE
-void __init reserve_bootmem(unsigned long addr, unsigned long size)
+int __init reserve_bootmem(unsigned long addr, unsigned long size,
+                           int flags)
 {
-       reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size);
+       return reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size, flags);
 }
 #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
 
index 81fb9bff0d4f9022db02f9d3194ebc5ccd0c350e..5357fcc4643b5a653c82d849690ababaeaec9a0e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/syscalls.h>
 #include <linux/cpuset.h>
 #include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */
+#include <linux/memcontrol.h>
 #include "internal.h"
 
 /*
@@ -118,6 +119,7 @@ void __remove_from_page_cache(struct page *page)
 {
        struct address_space *mapping = page->mapping;
 
+       mem_cgroup_uncharge_page(page);
        radix_tree_delete(&mapping->page_tree, page->index);
        page->mapping = NULL;
        mapping->nrpages--;
@@ -458,8 +460,12 @@ int filemap_write_and_wait_range(struct address_space *mapping,
 int add_to_page_cache(struct page *page, struct address_space *mapping,
                pgoff_t offset, gfp_t gfp_mask)
 {
-       int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
+       int error = mem_cgroup_cache_charge(page, current->mm,
+                                       gfp_mask & ~__GFP_HIGHMEM);
+       if (error)
+               goto out;
 
+       error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
        if (error == 0) {
                write_lock_irq(&mapping->tree_lock);
                error = radix_tree_insert(&mapping->page_tree, offset, page);
@@ -470,10 +476,14 @@ int add_to_page_cache(struct page *page, struct address_space *mapping,
                        page->index = offset;
                        mapping->nrpages++;
                        __inc_zone_page_state(page, NR_FILE_PAGES);
-               }
+               } else
+                       mem_cgroup_uncharge_page(page);
+
                write_unlock_irq(&mapping->tree_lock);
                radix_tree_preload_end();
-       }
+       } else
+               mem_cgroup_uncharge_page(page);
+out:
        return error;
 }
 EXPORT_SYMBOL(add_to_page_cache);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
new file mode 100644 (file)
index 0000000..5c2c702
--- /dev/null
@@ -0,0 +1,1192 @@
+/* memcontrol.c - Memory Controller
+ *
+ * Copyright IBM Corporation, 2007
+ * Author Balbir Singh <balbir@linux.vnet.ibm.com>
+ *
+ * Copyright 2007 OpenVZ SWsoft Inc
+ * Author: Pavel Emelianov <xemul@openvz.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.
+ */
+
+#include <linux/res_counter.h>
+#include <linux/memcontrol.h>
+#include <linux/cgroup.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/page-flags.h>
+#include <linux/backing-dev.h>
+#include <linux/bit_spinlock.h>
+#include <linux/rcupdate.h>
+#include <linux/swap.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/uaccess.h>
+
+struct cgroup_subsys mem_cgroup_subsys;
+static const int MEM_CGROUP_RECLAIM_RETRIES = 5;
+
+/*
+ * Statistics for memory cgroup.
+ */
+enum mem_cgroup_stat_index {
+       /*
+        * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss.
+        */
+       MEM_CGROUP_STAT_CACHE,     /* # of pages charged as cache */
+       MEM_CGROUP_STAT_RSS,       /* # of pages charged as rss */
+
+       MEM_CGROUP_STAT_NSTATS,
+};
+
+struct mem_cgroup_stat_cpu {
+       s64 count[MEM_CGROUP_STAT_NSTATS];
+} ____cacheline_aligned_in_smp;
+
+struct mem_cgroup_stat {
+       struct mem_cgroup_stat_cpu cpustat[NR_CPUS];
+};
+
+/*
+ * For accounting under irq disable, no need for increment preempt count.
+ */
+static void __mem_cgroup_stat_add_safe(struct mem_cgroup_stat *stat,
+               enum mem_cgroup_stat_index idx, int val)
+{
+       int cpu = smp_processor_id();
+       stat->cpustat[cpu].count[idx] += val;
+}
+
+static s64 mem_cgroup_read_stat(struct mem_cgroup_stat *stat,
+               enum mem_cgroup_stat_index idx)
+{
+       int cpu;
+       s64 ret = 0;
+       for_each_possible_cpu(cpu)
+               ret += stat->cpustat[cpu].count[idx];
+       return ret;
+}
+
+/*
+ * per-zone information in memory controller.
+ */
+
+enum mem_cgroup_zstat_index {
+       MEM_CGROUP_ZSTAT_ACTIVE,
+       MEM_CGROUP_ZSTAT_INACTIVE,
+
+       NR_MEM_CGROUP_ZSTAT,
+};
+
+struct mem_cgroup_per_zone {
+       /*
+        * spin_lock to protect the per cgroup LRU
+        */
+       spinlock_t              lru_lock;
+       struct list_head        active_list;
+       struct list_head        inactive_list;
+       unsigned long count[NR_MEM_CGROUP_ZSTAT];
+};
+/* Macro for accessing counter */
+#define MEM_CGROUP_ZSTAT(mz, idx)      ((mz)->count[(idx)])
+
+struct mem_cgroup_per_node {
+       struct mem_cgroup_per_zone zoneinfo[MAX_NR_ZONES];
+};
+
+struct mem_cgroup_lru_info {
+       struct mem_cgroup_per_node *nodeinfo[MAX_NUMNODES];
+};
+
+/*
+ * The memory controller data structure. The memory controller controls both
+ * page cache and RSS per cgroup. We would eventually like to provide
+ * statistics based on the statistics developed by Rik Van Riel for clock-pro,
+ * to help the administrator determine what knobs to tune.
+ *
+ * TODO: Add a water mark for the memory controller. Reclaim will begin when
+ * we hit the water mark. May be even add a low water mark, such that
+ * no reclaim occurs from a cgroup at it's low water mark, this is
+ * a feature that will be implemented much later in the future.
+ */
+struct mem_cgroup {
+       struct cgroup_subsys_state css;
+       /*
+        * the counter to account for memory usage
+        */
+       struct res_counter res;
+       /*
+        * Per cgroup active and inactive list, similar to the
+        * per zone LRU lists.
+        */
+       struct mem_cgroup_lru_info info;
+
+       int     prev_priority;  /* for recording reclaim priority */
+       /*
+        * statistics.
+        */
+       struct mem_cgroup_stat stat;
+};
+
+/*
+ * We use the lower bit of the page->page_cgroup pointer as a bit spin
+ * lock. We need to ensure that page->page_cgroup is atleast two
+ * byte aligned (based on comments from Nick Piggin)
+ */
+#define PAGE_CGROUP_LOCK_BIT   0x0
+#define PAGE_CGROUP_LOCK               (1 << PAGE_CGROUP_LOCK_BIT)
+
+/*
+ * A page_cgroup page is associated with every page descriptor. The
+ * page_cgroup helps us identify information about the cgroup
+ */
+struct page_cgroup {
+       struct list_head lru;           /* per cgroup LRU list */
+       struct page *page;
+       struct mem_cgroup *mem_cgroup;
+       atomic_t ref_cnt;               /* Helpful when pages move b/w  */
+                                       /* mapped and cached states     */
+       int      flags;
+};
+#define PAGE_CGROUP_FLAG_CACHE (0x1)   /* charged as cache */
+#define PAGE_CGROUP_FLAG_ACTIVE (0x2)  /* page is active in this cgroup */
+
+static inline int page_cgroup_nid(struct page_cgroup *pc)
+{
+       return page_to_nid(pc->page);
+}
+
+static inline enum zone_type page_cgroup_zid(struct page_cgroup *pc)
+{
+       return page_zonenum(pc->page);
+}
+
+enum {
+       MEM_CGROUP_TYPE_UNSPEC = 0,
+       MEM_CGROUP_TYPE_MAPPED,
+       MEM_CGROUP_TYPE_CACHED,
+       MEM_CGROUP_TYPE_ALL,
+       MEM_CGROUP_TYPE_MAX,
+};
+
+enum charge_type {
+       MEM_CGROUP_CHARGE_TYPE_CACHE = 0,
+       MEM_CGROUP_CHARGE_TYPE_MAPPED,
+};
+
+
+/*
+ * Always modified under lru lock. Then, not necessary to preempt_disable()
+ */
+static void mem_cgroup_charge_statistics(struct mem_cgroup *mem, int flags,
+                                       bool charge)
+{
+       int val = (charge)? 1 : -1;
+       struct mem_cgroup_stat *stat = &mem->stat;
+       VM_BUG_ON(!irqs_disabled());
+
+       if (flags & PAGE_CGROUP_FLAG_CACHE)
+               __mem_cgroup_stat_add_safe(stat,
+                                       MEM_CGROUP_STAT_CACHE, val);
+       else
+               __mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_RSS, val);
+}
+
+static inline struct mem_cgroup_per_zone *
+mem_cgroup_zoneinfo(struct mem_cgroup *mem, int nid, int zid)
+{
+       BUG_ON(!mem->info.nodeinfo[nid]);
+       return &mem->info.nodeinfo[nid]->zoneinfo[zid];
+}
+
+static inline struct mem_cgroup_per_zone *
+page_cgroup_zoneinfo(struct page_cgroup *pc)
+{
+       struct mem_cgroup *mem = pc->mem_cgroup;
+       int nid = page_cgroup_nid(pc);
+       int zid = page_cgroup_zid(pc);
+
+       return mem_cgroup_zoneinfo(mem, nid, zid);
+}
+
+static unsigned long mem_cgroup_get_all_zonestat(struct mem_cgroup *mem,
+                                       enum mem_cgroup_zstat_index idx)
+{
+       int nid, zid;
+       struct mem_cgroup_per_zone *mz;
+       u64 total = 0;
+
+       for_each_online_node(nid)
+               for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+                       mz = mem_cgroup_zoneinfo(mem, nid, zid);
+                       total += MEM_CGROUP_ZSTAT(mz, idx);
+               }
+       return total;
+}
+
+static struct mem_cgroup init_mem_cgroup;
+
+static inline
+struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont)
+{
+       return container_of(cgroup_subsys_state(cont,
+                               mem_cgroup_subsys_id), struct mem_cgroup,
+                               css);
+}
+
+static inline
+struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
+{
+       return container_of(task_subsys_state(p, mem_cgroup_subsys_id),
+                               struct mem_cgroup, css);
+}
+
+void mm_init_cgroup(struct mm_struct *mm, struct task_struct *p)
+{
+       struct mem_cgroup *mem;
+
+       mem = mem_cgroup_from_task(p);
+       css_get(&mem->css);
+       mm->mem_cgroup = mem;
+}
+
+void mm_free_cgroup(struct mm_struct *mm)
+{
+       css_put(&mm->mem_cgroup->css);
+}
+
+static inline int page_cgroup_locked(struct page *page)
+{
+       return bit_spin_is_locked(PAGE_CGROUP_LOCK_BIT,
+                                       &page->page_cgroup);
+}
+
+void page_assign_page_cgroup(struct page *page, struct page_cgroup *pc)
+{
+       int locked;
+
+       /*
+        * While resetting the page_cgroup we might not hold the
+        * page_cgroup lock. free_hot_cold_page() is an example
+        * of such a scenario
+        */
+       if (pc)
+               VM_BUG_ON(!page_cgroup_locked(page));
+       locked = (page->page_cgroup & PAGE_CGROUP_LOCK);
+       page->page_cgroup = ((unsigned long)pc | locked);
+}
+
+struct page_cgroup *page_get_page_cgroup(struct page *page)
+{
+       return (struct page_cgroup *)
+               (page->page_cgroup & ~PAGE_CGROUP_LOCK);
+}
+
+static void __always_inline lock_page_cgroup(struct page *page)
+{
+       bit_spin_lock(PAGE_CGROUP_LOCK_BIT, &page->page_cgroup);
+       VM_BUG_ON(!page_cgroup_locked(page));
+}
+
+static void __always_inline unlock_page_cgroup(struct page *page)
+{
+       bit_spin_unlock(PAGE_CGROUP_LOCK_BIT, &page->page_cgroup);
+}
+
+/*
+ * Tie new page_cgroup to struct page under lock_page_cgroup()
+ * This can fail if the page has been tied to a page_cgroup.
+ * If success, returns 0.
+ */
+static int page_cgroup_assign_new_page_cgroup(struct page *page,
+                                               struct page_cgroup *pc)
+{
+       int ret = 0;
+
+       lock_page_cgroup(page);
+       if (!page_get_page_cgroup(page))
+               page_assign_page_cgroup(page, pc);
+       else /* A page is tied to other pc. */
+               ret = 1;
+       unlock_page_cgroup(page);
+       return ret;
+}
+
+/*
+ * Clear page->page_cgroup member under lock_page_cgroup().
+ * If given "pc" value is different from one page->page_cgroup,
+ * page->cgroup is not cleared.
+ * Returns a value of page->page_cgroup at lock taken.
+ * A can can detect failure of clearing by following
+ *  clear_page_cgroup(page, pc) == pc
+ */
+
+static struct page_cgroup *clear_page_cgroup(struct page *page,
+                                               struct page_cgroup *pc)
+{
+       struct page_cgroup *ret;
+       /* lock and clear */
+       lock_page_cgroup(page);
+       ret = page_get_page_cgroup(page);
+       if (likely(ret == pc))
+               page_assign_page_cgroup(page, NULL);
+       unlock_page_cgroup(page);
+       return ret;
+}
+
+static void __mem_cgroup_remove_list(struct page_cgroup *pc)
+{
+       int from = pc->flags & PAGE_CGROUP_FLAG_ACTIVE;
+       struct mem_cgroup_per_zone *mz = page_cgroup_zoneinfo(pc);
+
+       if (from)
+               MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_ACTIVE) -= 1;
+       else
+               MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_INACTIVE) -= 1;
+
+       mem_cgroup_charge_statistics(pc->mem_cgroup, pc->flags, false);
+       list_del_init(&pc->lru);
+}
+
+static void __mem_cgroup_add_list(struct page_cgroup *pc)
+{
+       int to = pc->flags & PAGE_CGROUP_FLAG_ACTIVE;
+       struct mem_cgroup_per_zone *mz = page_cgroup_zoneinfo(pc);
+
+       if (!to) {
+               MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_INACTIVE) += 1;
+               list_add(&pc->lru, &mz->inactive_list);
+       } else {
+               MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_ACTIVE) += 1;
+               list_add(&pc->lru, &mz->active_list);
+       }
+       mem_cgroup_charge_statistics(pc->mem_cgroup, pc->flags, true);
+}
+
+static void __mem_cgroup_move_lists(struct page_cgroup *pc, bool active)
+{
+       int from = pc->flags & PAGE_CGROUP_FLAG_ACTIVE;
+       struct mem_cgroup_per_zone *mz = page_cgroup_zoneinfo(pc);
+
+       if (from)
+               MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_ACTIVE) -= 1;
+       else
+               MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_INACTIVE) -= 1;
+
+       if (active) {
+               MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_ACTIVE) += 1;
+               pc->flags |= PAGE_CGROUP_FLAG_ACTIVE;
+               list_move(&pc->lru, &mz->active_list);
+       } else {
+               MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_INACTIVE) += 1;
+               pc->flags &= ~PAGE_CGROUP_FLAG_ACTIVE;
+               list_move(&pc->lru, &mz->inactive_list);
+       }
+}
+
+int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem)
+{
+       int ret;
+
+       task_lock(task);
+       ret = task->mm && mm_cgroup(task->mm) == mem;
+       task_unlock(task);
+       return ret;
+}
+
+/*
+ * This routine assumes that the appropriate zone's lru lock is already held
+ */
+void mem_cgroup_move_lists(struct page_cgroup *pc, bool active)
+{
+       struct mem_cgroup_per_zone *mz;
+       unsigned long flags;
+
+       if (!pc)
+               return;
+
+       mz = page_cgroup_zoneinfo(pc);
+       spin_lock_irqsave(&mz->lru_lock, flags);
+       __mem_cgroup_move_lists(pc, active);
+       spin_unlock_irqrestore(&mz->lru_lock, flags);
+}
+
+/*
+ * Calculate mapped_ratio under memory controller. This will be used in
+ * vmscan.c for deteremining we have to reclaim mapped pages.
+ */
+int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem)
+{
+       long total, rss;
+
+       /*
+        * usage is recorded in bytes. But, here, we assume the number of
+        * physical pages can be represented by "long" on any arch.
+        */
+       total = (long) (mem->res.usage >> PAGE_SHIFT) + 1L;
+       rss = (long)mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS);
+       return (int)((rss * 100L) / total);
+}
+/*
+ * This function is called from vmscan.c. In page reclaiming loop. balance
+ * between active and inactive list is calculated. For memory controller
+ * page reclaiming, we should use using mem_cgroup's imbalance rather than
+ * zone's global lru imbalance.
+ */
+long mem_cgroup_reclaim_imbalance(struct mem_cgroup *mem)
+{
+       unsigned long active, inactive;
+       /* active and inactive are the number of pages. 'long' is ok.*/
+       active = mem_cgroup_get_all_zonestat(mem, MEM_CGROUP_ZSTAT_ACTIVE);
+       inactive = mem_cgroup_get_all_zonestat(mem, MEM_CGROUP_ZSTAT_INACTIVE);
+       return (long) (active / (inactive + 1));
+}
+
+/*
+ * prev_priority control...this will be used in memory reclaim path.
+ */
+int mem_cgroup_get_reclaim_priority(struct mem_cgroup *mem)
+{
+       return mem->prev_priority;
+}
+
+void mem_cgroup_note_reclaim_priority(struct mem_cgroup *mem, int priority)
+{
+       if (priority < mem->prev_priority)
+               mem->prev_priority = priority;
+}
+
+void mem_cgroup_record_reclaim_priority(struct mem_cgroup *mem, int priority)
+{
+       mem->prev_priority = priority;
+}
+
+/*
+ * Calculate # of pages to be scanned in this priority/zone.
+ * See also vmscan.c
+ *
+ * priority starts from "DEF_PRIORITY" and decremented in each loop.
+ * (see include/linux/mmzone.h)
+ */
+
+long mem_cgroup_calc_reclaim_active(struct mem_cgroup *mem,
+                                  struct zone *zone, int priority)
+{
+       long nr_active;
+       int nid = zone->zone_pgdat->node_id;
+       int zid = zone_idx(zone);
+       struct mem_cgroup_per_zone *mz = mem_cgroup_zoneinfo(mem, nid, zid);
+
+       nr_active = MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_ACTIVE);
+       return (nr_active >> priority);
+}
+
+long mem_cgroup_calc_reclaim_inactive(struct mem_cgroup *mem,
+                                       struct zone *zone, int priority)
+{
+       long nr_inactive;
+       int nid = zone->zone_pgdat->node_id;
+       int zid = zone_idx(zone);
+       struct mem_cgroup_per_zone *mz = mem_cgroup_zoneinfo(mem, nid, zid);
+
+       nr_inactive = MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_INACTIVE);
+
+       return (nr_inactive >> priority);
+}
+
+unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
+                                       struct list_head *dst,
+                                       unsigned long *scanned, int order,
+                                       int mode, struct zone *z,
+                                       struct mem_cgroup *mem_cont,
+                                       int active)
+{
+       unsigned long nr_taken = 0;
+       struct page *page;
+       unsigned long scan;
+       LIST_HEAD(pc_list);
+       struct list_head *src;
+       struct page_cgroup *pc, *tmp;
+       int nid = z->zone_pgdat->node_id;
+       int zid = zone_idx(z);
+       struct mem_cgroup_per_zone *mz;
+
+       mz = mem_cgroup_zoneinfo(mem_cont, nid, zid);
+       if (active)
+               src = &mz->active_list;
+       else
+               src = &mz->inactive_list;
+
+
+       spin_lock(&mz->lru_lock);
+       scan = 0;
+       list_for_each_entry_safe_reverse(pc, tmp, src, lru) {
+               if (scan >= nr_to_scan)
+                       break;
+               page = pc->page;
+               VM_BUG_ON(!pc);
+
+               if (unlikely(!PageLRU(page)))
+                       continue;
+
+               if (PageActive(page) && !active) {
+                       __mem_cgroup_move_lists(pc, true);
+                       continue;
+               }
+               if (!PageActive(page) && active) {
+                       __mem_cgroup_move_lists(pc, false);
+                       continue;
+               }
+
+               scan++;
+               list_move(&pc->lru, &pc_list);
+
+               if (__isolate_lru_page(page, mode) == 0) {
+                       list_move(&page->lru, dst);
+                       nr_taken++;
+               }
+       }
+
+       list_splice(&pc_list, src);
+       spin_unlock(&mz->lru_lock);
+
+       *scanned = scan;
+       return nr_taken;
+}
+
+/*
+ * Charge the memory controller for page usage.
+ * Return
+ * 0 if the charge was successful
+ * < 0 if the cgroup is over its limit
+ */
+static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
+                               gfp_t gfp_mask, enum charge_type ctype)
+{
+       struct mem_cgroup *mem;
+       struct page_cgroup *pc;
+       unsigned long flags;
+       unsigned long nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
+       struct mem_cgroup_per_zone *mz;
+
+       /*
+        * Should page_cgroup's go to their own slab?
+        * One could optimize the performance of the charging routine
+        * by saving a bit in the page_flags and using it as a lock
+        * to see if the cgroup page already has a page_cgroup associated
+        * with it
+        */
+retry:
+       if (page) {
+               lock_page_cgroup(page);
+               pc = page_get_page_cgroup(page);
+               /*
+                * The page_cgroup exists and
+                * the page has already been accounted.
+                */
+               if (pc) {
+                       if (unlikely(!atomic_inc_not_zero(&pc->ref_cnt))) {
+                               /* this page is under being uncharged ? */
+                               unlock_page_cgroup(page);
+                               cpu_relax();
+                               goto retry;
+                       } else {
+                               unlock_page_cgroup(page);
+                               goto done;
+                       }
+               }
+               unlock_page_cgroup(page);
+       }
+
+       pc = kzalloc(sizeof(struct page_cgroup), gfp_mask);
+       if (pc == NULL)
+               goto err;
+
+       /*
+        * We always charge the cgroup the mm_struct belongs to.
+        * The mm_struct's mem_cgroup changes on task migration if the
+        * thread group leader migrates. It's possible that mm is not
+        * set, if so charge the init_mm (happens for pagecache usage).
+        */
+       if (!mm)
+               mm = &init_mm;
+
+       rcu_read_lock();
+       mem = rcu_dereference(mm->mem_cgroup);
+       /*
+        * For every charge from the cgroup, increment reference
+        * count
+        */
+       css_get(&mem->css);
+       rcu_read_unlock();
+
+       /*
+        * If we created the page_cgroup, we should free it on exceeding
+        * the cgroup limit.
+        */
+       while (res_counter_charge(&mem->res, PAGE_SIZE)) {
+               if (!(gfp_mask & __GFP_WAIT))
+                       goto out;
+
+               if (try_to_free_mem_cgroup_pages(mem, gfp_mask))
+                       continue;
+
+               /*
+                * try_to_free_mem_cgroup_pages() might not give us a full
+                * picture of reclaim. Some pages are reclaimed and might be
+                * moved to swap cache or just unmapped from the cgroup.
+                * Check the limit again to see if the reclaim reduced the
+                * current usage of the cgroup before giving up
+                */
+               if (res_counter_check_under_limit(&mem->res))
+                       continue;
+
+               if (!nr_retries--) {
+                       mem_cgroup_out_of_memory(mem, gfp_mask);
+                       goto out;
+               }
+               congestion_wait(WRITE, HZ/10);
+       }
+
+       atomic_set(&pc->ref_cnt, 1);
+       pc->mem_cgroup = mem;
+       pc->page = page;
+       pc->flags = PAGE_CGROUP_FLAG_ACTIVE;
+       if (ctype == MEM_CGROUP_CHARGE_TYPE_CACHE)
+               pc->flags |= PAGE_CGROUP_FLAG_CACHE;
+
+       if (!page || page_cgroup_assign_new_page_cgroup(page, pc)) {
+               /*
+                * Another charge has been added to this page already.
+                * We take lock_page_cgroup(page) again and read
+                * page->cgroup, increment refcnt.... just retry is OK.
+                */
+               res_counter_uncharge(&mem->res, PAGE_SIZE);
+               css_put(&mem->css);
+               kfree(pc);
+               if (!page)
+                       goto done;
+               goto retry;
+       }
+
+       mz = page_cgroup_zoneinfo(pc);
+       spin_lock_irqsave(&mz->lru_lock, flags);
+       /* Update statistics vector */
+       __mem_cgroup_add_list(pc);
+       spin_unlock_irqrestore(&mz->lru_lock, flags);
+
+done:
+       return 0;
+out:
+       css_put(&mem->css);
+       kfree(pc);
+err:
+       return -ENOMEM;
+}
+
+int mem_cgroup_charge(struct page *page, struct mm_struct *mm,
+                       gfp_t gfp_mask)
+{
+       return mem_cgroup_charge_common(page, mm, gfp_mask,
+                       MEM_CGROUP_CHARGE_TYPE_MAPPED);
+}
+
+/*
+ * See if the cached pages should be charged at all?
+ */
+int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
+                               gfp_t gfp_mask)
+{
+       int ret = 0;
+       if (!mm)
+               mm = &init_mm;
+
+       ret = mem_cgroup_charge_common(page, mm, gfp_mask,
+                               MEM_CGROUP_CHARGE_TYPE_CACHE);
+       return ret;
+}
+
+/*
+ * Uncharging is always a welcome operation, we never complain, simply
+ * uncharge. This routine should be called with lock_page_cgroup held
+ */
+void mem_cgroup_uncharge(struct page_cgroup *pc)
+{
+       struct mem_cgroup *mem;
+       struct mem_cgroup_per_zone *mz;
+       struct page *page;
+       unsigned long flags;
+
+       /*
+        * Check if our page_cgroup is valid
+        */
+       if (!pc)
+               return;
+
+       if (atomic_dec_and_test(&pc->ref_cnt)) {
+               page = pc->page;
+               mz = page_cgroup_zoneinfo(pc);
+               /*
+                * get page->cgroup and clear it under lock.
+                * force_empty can drop page->cgroup without checking refcnt.
+                */
+               unlock_page_cgroup(page);
+               if (clear_page_cgroup(page, pc) == pc) {
+                       mem = pc->mem_cgroup;
+                       css_put(&mem->css);
+                       res_counter_uncharge(&mem->res, PAGE_SIZE);
+                       spin_lock_irqsave(&mz->lru_lock, flags);
+                       __mem_cgroup_remove_list(pc);
+                       spin_unlock_irqrestore(&mz->lru_lock, flags);
+                       kfree(pc);
+               }
+               lock_page_cgroup(page);
+       }
+}
+
+void mem_cgroup_uncharge_page(struct page *page)
+{
+       lock_page_cgroup(page);
+       mem_cgroup_uncharge(page_get_page_cgroup(page));
+       unlock_page_cgroup(page);
+}
+
+/*
+ * Returns non-zero if a page (under migration) has valid page_cgroup member.
+ * Refcnt of page_cgroup is incremented.
+ */
+
+int mem_cgroup_prepare_migration(struct page *page)
+{
+       struct page_cgroup *pc;
+       int ret = 0;
+       lock_page_cgroup(page);
+       pc = page_get_page_cgroup(page);
+       if (pc && atomic_inc_not_zero(&pc->ref_cnt))
+               ret = 1;
+       unlock_page_cgroup(page);
+       return ret;
+}
+
+void mem_cgroup_end_migration(struct page *page)
+{
+       struct page_cgroup *pc;
+
+       lock_page_cgroup(page);
+       pc = page_get_page_cgroup(page);
+       mem_cgroup_uncharge(pc);
+       unlock_page_cgroup(page);
+}
+/*
+ * We know both *page* and *newpage* are now not-on-LRU and Pg_locked.
+ * And no race with uncharge() routines because page_cgroup for *page*
+ * has extra one reference by mem_cgroup_prepare_migration.
+ */
+
+void mem_cgroup_page_migration(struct page *page, struct page *newpage)
+{
+       struct page_cgroup *pc;
+       struct mem_cgroup *mem;
+       unsigned long flags;
+       struct mem_cgroup_per_zone *mz;
+retry:
+       pc = page_get_page_cgroup(page);
+       if (!pc)
+               return;
+       mem = pc->mem_cgroup;
+       mz = page_cgroup_zoneinfo(pc);
+       if (clear_page_cgroup(page, pc) != pc)
+               goto retry;
+       spin_lock_irqsave(&mz->lru_lock, flags);
+
+       __mem_cgroup_remove_list(pc);
+       spin_unlock_irqrestore(&mz->lru_lock, flags);
+
+       pc->page = newpage;
+       lock_page_cgroup(newpage);
+       page_assign_page_cgroup(newpage, pc);
+       unlock_page_cgroup(newpage);
+
+       mz = page_cgroup_zoneinfo(pc);
+       spin_lock_irqsave(&mz->lru_lock, flags);
+       __mem_cgroup_add_list(pc);
+       spin_unlock_irqrestore(&mz->lru_lock, flags);
+       return;
+}
+
+/*
+ * This routine traverse page_cgroup in given list and drop them all.
+ * This routine ignores page_cgroup->ref_cnt.
+ * *And* this routine doesn't reclaim page itself, just removes page_cgroup.
+ */
+#define FORCE_UNCHARGE_BATCH   (128)
+static void
+mem_cgroup_force_empty_list(struct mem_cgroup *mem,
+                           struct mem_cgroup_per_zone *mz,
+                           int active)
+{
+       struct page_cgroup *pc;
+       struct page *page;
+       int count;
+       unsigned long flags;
+       struct list_head *list;
+
+       if (active)
+               list = &mz->active_list;
+       else
+               list = &mz->inactive_list;
+
+       if (list_empty(list))
+               return;
+retry:
+       count = FORCE_UNCHARGE_BATCH;
+       spin_lock_irqsave(&mz->lru_lock, flags);
+
+       while (--count && !list_empty(list)) {
+               pc = list_entry(list->prev, struct page_cgroup, lru);
+               page = pc->page;
+               /* Avoid race with charge */
+               atomic_set(&pc->ref_cnt, 0);
+               if (clear_page_cgroup(page, pc) == pc) {
+                       css_put(&mem->css);
+                       res_counter_uncharge(&mem->res, PAGE_SIZE);
+                       __mem_cgroup_remove_list(pc);
+                       kfree(pc);
+               } else  /* being uncharged ? ...do relax */
+                       break;
+       }
+       spin_unlock_irqrestore(&mz->lru_lock, flags);
+       if (!list_empty(list)) {
+               cond_resched();
+               goto retry;
+       }
+       return;
+}
+
+/*
+ * make mem_cgroup's charge to be 0 if there is no task.
+ * This enables deleting this mem_cgroup.
+ */
+
+int mem_cgroup_force_empty(struct mem_cgroup *mem)
+{
+       int ret = -EBUSY;
+       int node, zid;
+       css_get(&mem->css);
+       /*
+        * page reclaim code (kswapd etc..) will move pages between
+`       * active_list <-> inactive_list while we don't take a lock.
+        * So, we have to do loop here until all lists are empty.
+        */
+       while (mem->res.usage > 0) {
+               if (atomic_read(&mem->css.cgroup->count) > 0)
+                       goto out;
+               for_each_node_state(node, N_POSSIBLE)
+                       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+                               struct mem_cgroup_per_zone *mz;
+                               mz = mem_cgroup_zoneinfo(mem, node, zid);
+                               /* drop all page_cgroup in active_list */
+                               mem_cgroup_force_empty_list(mem, mz, 1);
+                               /* drop all page_cgroup in inactive_list */
+                               mem_cgroup_force_empty_list(mem, mz, 0);
+                       }
+       }
+       ret = 0;
+out:
+       css_put(&mem->css);
+       return ret;
+}
+
+
+
+int mem_cgroup_write_strategy(char *buf, unsigned long long *tmp)
+{
+       *tmp = memparse(buf, &buf);
+       if (*buf != '\0')
+               return -EINVAL;
+
+       /*
+        * Round up the value to the closest page size
+        */
+       *tmp = ((*tmp + PAGE_SIZE - 1) >> PAGE_SHIFT) << PAGE_SHIFT;
+       return 0;
+}
+
+static ssize_t mem_cgroup_read(struct cgroup *cont,
+                       struct cftype *cft, struct file *file,
+                       char __user *userbuf, size_t nbytes, loff_t *ppos)
+{
+       return res_counter_read(&mem_cgroup_from_cont(cont)->res,
+                               cft->private, userbuf, nbytes, ppos,
+                               NULL);
+}
+
+static ssize_t mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
+                               struct file *file, const char __user *userbuf,
+                               size_t nbytes, loff_t *ppos)
+{
+       return res_counter_write(&mem_cgroup_from_cont(cont)->res,
+                               cft->private, userbuf, nbytes, ppos,
+                               mem_cgroup_write_strategy);
+}
+
+static ssize_t mem_force_empty_write(struct cgroup *cont,
+                               struct cftype *cft, struct file *file,
+                               const char __user *userbuf,
+                               size_t nbytes, loff_t *ppos)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
+       int ret;
+       ret = mem_cgroup_force_empty(mem);
+       if (!ret)
+               ret = nbytes;
+       return ret;
+}
+
+/*
+ * Note: This should be removed if cgroup supports write-only file.
+ */
+
+static ssize_t mem_force_empty_read(struct cgroup *cont,
+                               struct cftype *cft,
+                               struct file *file, char __user *userbuf,
+                               size_t nbytes, loff_t *ppos)
+{
+       return -EINVAL;
+}
+
+
+static const struct mem_cgroup_stat_desc {
+       const char *msg;
+       u64 unit;
+} mem_cgroup_stat_desc[] = {
+       [MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, },
+       [MEM_CGROUP_STAT_RSS] = { "rss", PAGE_SIZE, },
+};
+
+static int mem_control_stat_show(struct seq_file *m, void *arg)
+{
+       struct cgroup *cont = m->private;
+       struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont);
+       struct mem_cgroup_stat *stat = &mem_cont->stat;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(stat->cpustat[0].count); i++) {
+               s64 val;
+
+               val = mem_cgroup_read_stat(stat, i);
+               val *= mem_cgroup_stat_desc[i].unit;
+               seq_printf(m, "%s %lld\n", mem_cgroup_stat_desc[i].msg,
+                               (long long)val);
+       }
+       /* showing # of active pages */
+       {
+               unsigned long active, inactive;
+
+               inactive = mem_cgroup_get_all_zonestat(mem_cont,
+                                               MEM_CGROUP_ZSTAT_INACTIVE);
+               active = mem_cgroup_get_all_zonestat(mem_cont,
+                                               MEM_CGROUP_ZSTAT_ACTIVE);
+               seq_printf(m, "active %ld\n", (active) * PAGE_SIZE);
+               seq_printf(m, "inactive %ld\n", (inactive) * PAGE_SIZE);
+       }
+       return 0;
+}
+
+static const struct file_operations mem_control_stat_file_operations = {
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int mem_control_stat_open(struct inode *unused, struct file *file)
+{
+       /* XXX __d_cont */
+       struct cgroup *cont = file->f_dentry->d_parent->d_fsdata;
+
+       file->f_op = &mem_control_stat_file_operations;
+       return single_open(file, mem_control_stat_show, cont);
+}
+
+
+
+static struct cftype mem_cgroup_files[] = {
+       {
+               .name = "usage_in_bytes",
+               .private = RES_USAGE,
+               .read = mem_cgroup_read,
+       },
+       {
+               .name = "limit_in_bytes",
+               .private = RES_LIMIT,
+               .write = mem_cgroup_write,
+               .read = mem_cgroup_read,
+       },
+       {
+               .name = "failcnt",
+               .private = RES_FAILCNT,
+               .read = mem_cgroup_read,
+       },
+       {
+               .name = "force_empty",
+               .write = mem_force_empty_write,
+               .read = mem_force_empty_read,
+       },
+       {
+               .name = "stat",
+               .open = mem_control_stat_open,
+       },
+};
+
+static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *mem, int node)
+{
+       struct mem_cgroup_per_node *pn;
+       struct mem_cgroup_per_zone *mz;
+       int zone;
+       /*
+        * This routine is called against possible nodes.
+        * But it's BUG to call kmalloc() against offline node.
+        *
+        * TODO: this routine can waste much memory for nodes which will
+        *       never be onlined. It's better to use memory hotplug callback
+        *       function.
+        */
+       if (node_state(node, N_HIGH_MEMORY))
+               pn = kmalloc_node(sizeof(*pn), GFP_KERNEL, node);
+       else
+               pn = kmalloc(sizeof(*pn), GFP_KERNEL);
+       if (!pn)
+               return 1;
+
+       mem->info.nodeinfo[node] = pn;
+       memset(pn, 0, sizeof(*pn));
+
+       for (zone = 0; zone < MAX_NR_ZONES; zone++) {
+               mz = &pn->zoneinfo[zone];
+               INIT_LIST_HEAD(&mz->active_list);
+               INIT_LIST_HEAD(&mz->inactive_list);
+               spin_lock_init(&mz->lru_lock);
+       }
+       return 0;
+}
+
+static void free_mem_cgroup_per_zone_info(struct mem_cgroup *mem, int node)
+{
+       kfree(mem->info.nodeinfo[node]);
+}
+
+
+static struct mem_cgroup init_mem_cgroup;
+
+static struct cgroup_subsys_state *
+mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
+{
+       struct mem_cgroup *mem;
+       int node;
+
+       if (unlikely((cont->parent) == NULL)) {
+               mem = &init_mem_cgroup;
+               init_mm.mem_cgroup = mem;
+       } else
+               mem = kzalloc(sizeof(struct mem_cgroup), GFP_KERNEL);
+
+       if (mem == NULL)
+               return NULL;
+
+       res_counter_init(&mem->res);
+
+       memset(&mem->info, 0, sizeof(mem->info));
+
+       for_each_node_state(node, N_POSSIBLE)
+               if (alloc_mem_cgroup_per_zone_info(mem, node))
+                       goto free_out;
+
+       return &mem->css;
+free_out:
+       for_each_node_state(node, N_POSSIBLE)
+               free_mem_cgroup_per_zone_info(mem, node);
+       if (cont->parent != NULL)
+               kfree(mem);
+       return NULL;
+}
+
+static void mem_cgroup_pre_destroy(struct cgroup_subsys *ss,
+                                       struct cgroup *cont)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
+       mem_cgroup_force_empty(mem);
+}
+
+static void mem_cgroup_destroy(struct cgroup_subsys *ss,
+                               struct cgroup *cont)
+{
+       int node;
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
+
+       for_each_node_state(node, N_POSSIBLE)
+               free_mem_cgroup_per_zone_info(mem, node);
+
+       kfree(mem_cgroup_from_cont(cont));
+}
+
+static int mem_cgroup_populate(struct cgroup_subsys *ss,
+                               struct cgroup *cont)
+{
+       return cgroup_add_files(cont, ss, mem_cgroup_files,
+                                       ARRAY_SIZE(mem_cgroup_files));
+}
+
+static void mem_cgroup_move_task(struct cgroup_subsys *ss,
+                               struct cgroup *cont,
+                               struct cgroup *old_cont,
+                               struct task_struct *p)
+{
+       struct mm_struct *mm;
+       struct mem_cgroup *mem, *old_mem;
+
+       mm = get_task_mm(p);
+       if (mm == NULL)
+               return;
+
+       mem = mem_cgroup_from_cont(cont);
+       old_mem = mem_cgroup_from_cont(old_cont);
+
+       if (mem == old_mem)
+               goto out;
+
+       /*
+        * Only thread group leaders are allowed to migrate, the mm_struct is
+        * in effect owned by the leader
+        */
+       if (p->tgid != p->pid)
+               goto out;
+
+       css_get(&mem->css);
+       rcu_assign_pointer(mm->mem_cgroup, mem);
+       css_put(&old_mem->css);
+
+out:
+       mmput(mm);
+       return;
+}
+
+struct cgroup_subsys mem_cgroup_subsys = {
+       .name = "memory",
+       .subsys_id = mem_cgroup_subsys_id,
+       .create = mem_cgroup_create,
+       .pre_destroy = mem_cgroup_pre_destroy,
+       .destroy = mem_cgroup_destroy,
+       .populate = mem_cgroup_populate,
+       .attach = mem_cgroup_move_task,
+       .early_init = 0,
+};
index 7bb70728bb526f357deca4879f821038a2b9fd62..153a54b2013ca9927edf1dda4e047a82a952c05e 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/delayacct.h>
 #include <linux/init.h>
 #include <linux/writeback.h>
+#include <linux/memcontrol.h>
 
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
@@ -82,7 +83,18 @@ void * high_memory;
 EXPORT_SYMBOL(num_physpages);
 EXPORT_SYMBOL(high_memory);
 
-int randomize_va_space __read_mostly = 1;
+/*
+ * Randomize the address space (stacks, mmaps, brk, etc.).
+ *
+ * ( When CONFIG_COMPAT_BRK=y we exclude brk from randomization,
+ *   as ancient (libc5 based) binaries can segfault. )
+ */
+int randomize_va_space __read_mostly =
+#ifdef CONFIG_COMPAT_BRK
+                                       1;
+#else
+                                       2;
+#endif
 
 static int __init disable_randmaps(char *s)
 {
@@ -1133,16 +1145,20 @@ static int insert_page(struct mm_struct *mm, unsigned long addr, struct page *pa
 {
        int retval;
        pte_t *pte;
-       spinlock_t *ptl;  
+       spinlock_t *ptl;
+
+       retval = mem_cgroup_charge(page, mm, GFP_KERNEL);
+       if (retval)
+               goto out;
 
        retval = -EINVAL;
        if (PageAnon(page))
-               goto out;
+               goto out_uncharge;
        retval = -ENOMEM;
        flush_dcache_page(page);
        pte = get_locked_pte(mm, addr, &ptl);
        if (!pte)
-               goto out;
+               goto out_uncharge;
        retval = -EBUSY;
        if (!pte_none(*pte))
                goto out_unlock;
@@ -1154,8 +1170,12 @@ static int insert_page(struct mm_struct *mm, unsigned long addr, struct page *pa
        set_pte_at(mm, addr, pte, mk_pte(page, prot));
 
        retval = 0;
+       pte_unmap_unlock(pte, ptl);
+       return retval;
 out_unlock:
        pte_unmap_unlock(pte, ptl);
+out_uncharge:
+       mem_cgroup_uncharge_page(page);
 out:
        return retval;
 }
@@ -1630,6 +1650,9 @@ gotten:
        cow_user_page(new_page, old_page, address, vma);
        __SetPageUptodate(new_page);
 
+       if (mem_cgroup_charge(new_page, mm, GFP_KERNEL))
+               goto oom_free_new;
+
        /*
         * Re-check the pte - we dropped the lock
         */
@@ -1661,7 +1684,9 @@ gotten:
                /* Free the old page.. */
                new_page = old_page;
                ret |= VM_FAULT_WRITE;
-       }
+       } else
+               mem_cgroup_uncharge_page(new_page);
+
        if (new_page)
                page_cache_release(new_page);
        if (old_page)
@@ -1685,6 +1710,8 @@ unlock:
                put_page(dirty_page);
        }
        return ret;
+oom_free_new:
+       __free_page(new_page);
 oom:
        if (old_page)
                page_cache_release(old_page);
@@ -2025,6 +2052,12 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
                count_vm_event(PGMAJFAULT);
        }
 
+       if (mem_cgroup_charge(page, mm, GFP_KERNEL)) {
+               delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
+               ret = VM_FAULT_OOM;
+               goto out;
+       }
+
        mark_page_accessed(page);
        lock_page(page);
        delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
@@ -2062,8 +2095,10 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (write_access) {
                /* XXX: We could OR the do_wp_page code with this one? */
                if (do_wp_page(mm, vma, address,
-                               page_table, pmd, ptl, pte) & VM_FAULT_OOM)
+                               page_table, pmd, ptl, pte) & VM_FAULT_OOM) {
+                       mem_cgroup_uncharge_page(page);
                        ret = VM_FAULT_OOM;
+               }
                goto out;
        }
 
@@ -2074,6 +2109,7 @@ unlock:
 out:
        return ret;
 out_nomap:
+       mem_cgroup_uncharge_page(page);
        pte_unmap_unlock(page_table, ptl);
        unlock_page(page);
        page_cache_release(page);
@@ -2103,6 +2139,9 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
                goto oom;
        __SetPageUptodate(page);
 
+       if (mem_cgroup_charge(page, mm, GFP_KERNEL))
+               goto oom_free_page;
+
        entry = mk_pte(page, vma->vm_page_prot);
        entry = maybe_mkwrite(pte_mkdirty(entry), vma);
 
@@ -2120,8 +2159,11 @@ unlock:
        pte_unmap_unlock(page_table, ptl);
        return 0;
 release:
+       mem_cgroup_uncharge_page(page);
        page_cache_release(page);
        goto unlock;
+oom_free_page:
+       __free_page(page);
 oom:
        return VM_FAULT_OOM;
 }
@@ -2235,6 +2277,11 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
 
        }
 
+       if (mem_cgroup_charge(page, mm, GFP_KERNEL)) {
+               ret = VM_FAULT_OOM;
+               goto out;
+       }
+
        page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
 
        /*
@@ -2270,6 +2317,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                /* no need to invalidate: a not-present page won't be cached */
                update_mmu_cache(vma, address, entry);
        } else {
+               mem_cgroup_uncharge_page(page);
                if (anon)
                        page_cache_release(page);
                else
index 857a987e36904a5850a4d663c6d9e41e494ffe1f..a73504ff5ab982007b2e0355e49f0dedcac65899 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mempolicy.h>
 #include <linux/vmalloc.h>
 #include <linux/security.h>
+#include <linux/memcontrol.h>
 
 #include "internal.h"
 
@@ -152,6 +153,11 @@ static void remove_migration_pte(struct vm_area_struct *vma,
                return;
        }
 
+       if (mem_cgroup_charge(new, mm, GFP_KERNEL)) {
+               pte_unmap(ptep);
+               return;
+       }
+
        ptl = pte_lockptr(mm, pmd);
        spin_lock(ptl);
        pte = *ptep;
@@ -587,9 +593,10 @@ static int move_to_new_page(struct page *newpage, struct page *page)
        else
                rc = fallback_migrate_page(mapping, newpage, page);
 
-       if (!rc)
+       if (!rc) {
+               mem_cgroup_page_migration(page, newpage);
                remove_migration_ptes(page, newpage);
-       else
+       else
                newpage->mapping = NULL;
 
        unlock_page(newpage);
@@ -608,6 +615,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        int *result = NULL;
        struct page *newpage = get_new_page(page, private, &result);
        int rcu_locked = 0;
+       int charge = 0;
 
        if (!newpage)
                return -ENOMEM;
@@ -667,14 +675,19 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                goto rcu_unlock;
        }
 
+       charge = mem_cgroup_prepare_migration(page);
        /* Establish migration ptes or remove ptes */
        try_to_unmap(page, 1);
 
        if (!page_mapped(page))
                rc = move_to_new_page(newpage, page);
 
-       if (rc)
+       if (rc) {
                remove_migration_ptes(page, page);
+               if (charge)
+                       mem_cgroup_end_migration(page);
+       } else if (charge)
+               mem_cgroup_end_migration(newpage);
 rcu_unlock:
        if (rcu_locked)
                rcu_read_unlock();
index bb4c963cc5347f695de8a060336e877278bbed81..ad6e4eaf34f81ae27a684935ed7ff76960f17761 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -245,7 +245,7 @@ asmlinkage unsigned long sys_brk(unsigned long brk)
 
        down_write(&mm->mmap_sem);
 
-       if (brk < mm->end_code)
+       if (brk < mm->start_brk)
                goto out;
 
        /*
index c1850bf991cda9794f6985a7f6ebf595c6adac87..4194b9db0104d54dea5ea871e0e111695fa49cba 100644 (file)
 #include <linux/cpuset.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
+#include <linux/memcontrol.h>
 
 int sysctl_panic_on_oom;
 int sysctl_oom_kill_allocating_task;
+int sysctl_oom_dump_tasks;
 static DEFINE_SPINLOCK(zone_scan_mutex);
 /* #define DEBUG */
 
@@ -50,7 +52,8 @@ static DEFINE_SPINLOCK(zone_scan_mutex);
  *    of least surprise ... (be careful when you change it)
  */
 
-unsigned long badness(struct task_struct *p, unsigned long uptime)
+unsigned long badness(struct task_struct *p, unsigned long uptime,
+                       struct mem_cgroup *mem)
 {
        unsigned long points, cpu_time, run_time, s;
        struct mm_struct *mm;
@@ -193,7 +196,8 @@ static inline enum oom_constraint constrained_alloc(struct zonelist *zonelist,
  *
  * (not docbooked, we don't want this one cluttering up the manual)
  */
-static struct task_struct *select_bad_process(unsigned long *ppoints)
+static struct task_struct *select_bad_process(unsigned long *ppoints,
+                                               struct mem_cgroup *mem)
 {
        struct task_struct *g, *p;
        struct task_struct *chosen = NULL;
@@ -213,6 +217,8 @@ static struct task_struct *select_bad_process(unsigned long *ppoints)
                /* skip the init task */
                if (is_global_init(p))
                        continue;
+               if (mem && !task_in_mem_cgroup(p, mem))
+                       continue;
 
                /*
                 * This task already has access to memory reserves and is
@@ -247,7 +253,7 @@ static struct task_struct *select_bad_process(unsigned long *ppoints)
                if (p->oomkilladj == OOM_DISABLE)
                        continue;
 
-               points = badness(p, uptime.tv_sec);
+               points = badness(p, uptime.tv_sec, mem);
                if (points > *ppoints || !chosen) {
                        chosen = p;
                        *ppoints = points;
@@ -257,6 +263,41 @@ static struct task_struct *select_bad_process(unsigned long *ppoints)
        return chosen;
 }
 
+/**
+ * Dumps the current memory state of all system tasks, excluding kernel threads.
+ * State information includes task's pid, uid, tgid, vm size, rss, cpu, oom_adj
+ * score, and name.
+ *
+ * If the actual is non-NULL, only tasks that are a member of the mem_cgroup are
+ * shown.
+ *
+ * Call with tasklist_lock read-locked.
+ */
+static void dump_tasks(const struct mem_cgroup *mem)
+{
+       struct task_struct *g, *p;
+
+       printk(KERN_INFO "[ pid ]   uid  tgid total_vm      rss cpu oom_adj "
+              "name\n");
+       do_each_thread(g, p) {
+               /*
+                * total_vm and rss sizes do not exist for tasks with a
+                * detached mm so there's no need to report them.
+                */
+               if (!p->mm)
+                       continue;
+               if (mem && !task_in_mem_cgroup(p, mem))
+                       continue;
+
+               task_lock(p);
+               printk(KERN_INFO "[%5d] %5d %5d %8lu %8lu %3d     %3d %s\n",
+                      p->pid, p->uid, p->tgid, p->mm->total_vm,
+                      get_mm_rss(p->mm), (int)task_cpu(p), p->oomkilladj,
+                      p->comm);
+               task_unlock(p);
+       } while_each_thread(g, p);
+}
+
 /**
  * Send SIGKILL to the selected  process irrespective of  CAP_SYS_RAW_IO
  * flag though it's unlikely that  we select a process with CAP_SYS_RAW_IO
@@ -334,7 +375,8 @@ static int oom_kill_task(struct task_struct *p)
 }
 
 static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
-                           unsigned long points, const char *message)
+                           unsigned long points, struct mem_cgroup *mem,
+                           const char *message)
 {
        struct task_struct *c;
 
@@ -344,6 +386,8 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                        current->comm, gfp_mask, order, current->oomkilladj);
                dump_stack();
                show_mem();
+               if (sysctl_oom_dump_tasks)
+                       dump_tasks(mem);
        }
 
        /*
@@ -368,6 +412,31 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
        return oom_kill_task(p);
 }
 
+#ifdef CONFIG_CGROUP_MEM_CONT
+void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
+{
+       unsigned long points = 0;
+       struct task_struct *p;
+
+       cgroup_lock();
+       rcu_read_lock();
+retry:
+       p = select_bad_process(&points, mem);
+       if (PTR_ERR(p) == -1UL)
+               goto out;
+
+       if (!p)
+               p = current;
+
+       if (oom_kill_process(p, gfp_mask, 0, points, mem,
+                               "Memory cgroup out of memory"))
+               goto retry;
+out:
+       rcu_read_unlock();
+       cgroup_unlock();
+}
+#endif
+
 static BLOCKING_NOTIFIER_HEAD(oom_notify_list);
 
 int register_oom_notifier(struct notifier_block *nb)
@@ -465,7 +534,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order)
 
        switch (constraint) {
        case CONSTRAINT_MEMORY_POLICY:
-               oom_kill_process(current, gfp_mask, order, points,
+               oom_kill_process(current, gfp_mask, order, points, NULL,
                                "No available memory (MPOL_BIND)");
                break;
 
@@ -475,7 +544,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order)
                /* Fall-through */
        case CONSTRAINT_CPUSET:
                if (sysctl_oom_kill_allocating_task) {
-                       oom_kill_process(current, gfp_mask, order, points,
+                       oom_kill_process(current, gfp_mask, order, points, NULL,
                                        "Out of memory (oom_kill_allocating_task)");
                        break;
                }
@@ -484,7 +553,7 @@ retry:
                 * Rambo mode: Shoot down a process and hope it solves whatever
                 * issues we may have.
                 */
-               p = select_bad_process(&points);
+               p = select_bad_process(&points, NULL);
 
                if (PTR_ERR(p) == -1UL)
                        goto out;
@@ -495,7 +564,7 @@ retry:
                        panic("Out of memory and no killable processes...\n");
                }
 
-               if (oom_kill_process(p, gfp_mask, order, points,
+               if (oom_kill_process(p, gfp_mask, order, points, NULL,
                                     "Out of memory"))
                        goto retry;
 
index 37576b822f06c98c2d3342af1cdecbe0e5a8f25b..26a54a17dc9f5dfc0191da8f0dd774476ab8eee0 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/backing-dev.h>
 #include <linux/fault-inject.h>
 #include <linux/page-isolation.h>
+#include <linux/memcontrol.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -987,6 +988,7 @@ static void free_hot_cold_page(struct page *page, int cold)
 
        if (!PageHighMem(page))
                debug_check_no_locks_freed(page_address(page), PAGE_SIZE);
+       VM_BUG_ON(page_get_page_cgroup(page));
        arch_free_page(page, 0);
        kernel_map_pages(page, 1, 0);
 
@@ -2525,6 +2527,7 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
                set_page_links(page, zone, nid, pfn);
                init_page_count(page);
                reset_page_mapcount(page);
+               page_assign_page_cgroup(page, NULL);
                SetPageReserved(page);
 
                /*
index 57ad276900c94903a2febd53e1c0d995958a38a9..a0e92a263d12eb734e8a8171e9d575e35dc0d768 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -48,6 +48,7 @@
 #include <linux/rcupdate.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/memcontrol.h>
 
 #include <asm/tlbflush.h>
 
@@ -301,7 +302,8 @@ out:
        return referenced;
 }
 
-static int page_referenced_anon(struct page *page)
+static int page_referenced_anon(struct page *page,
+                               struct mem_cgroup *mem_cont)
 {
        unsigned int mapcount;
        struct anon_vma *anon_vma;
@@ -314,6 +316,13 @@ static int page_referenced_anon(struct page *page)
 
        mapcount = page_mapcount(page);
        list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
+               /*
+                * If we are reclaiming on behalf of a cgroup, skip
+                * counting on behalf of references from different
+                * cgroups
+                */
+               if (mem_cont && (mm_cgroup(vma->vm_mm) != mem_cont))
+                       continue;
                referenced += page_referenced_one(page, vma, &mapcount);
                if (!mapcount)
                        break;
@@ -334,7 +343,8 @@ static int page_referenced_anon(struct page *page)
  *
  * This function is only called from page_referenced for object-based pages.
  */
-static int page_referenced_file(struct page *page)
+static int page_referenced_file(struct page *page,
+                               struct mem_cgroup *mem_cont)
 {
        unsigned int mapcount;
        struct address_space *mapping = page->mapping;
@@ -367,6 +377,13 @@ static int page_referenced_file(struct page *page)
        mapcount = page_mapcount(page);
 
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
+               /*
+                * If we are reclaiming on behalf of a cgroup, skip
+                * counting on behalf of references from different
+                * cgroups
+                */
+               if (mem_cont && (mm_cgroup(vma->vm_mm) != mem_cont))
+                       continue;
                if ((vma->vm_flags & (VM_LOCKED|VM_MAYSHARE))
                                  == (VM_LOCKED|VM_MAYSHARE)) {
                        referenced++;
@@ -389,7 +406,8 @@ static int page_referenced_file(struct page *page)
  * Quick test_and_clear_referenced for all mappings to a page,
  * returns the number of ptes which referenced the page.
  */
-int page_referenced(struct page *page, int is_locked)
+int page_referenced(struct page *page, int is_locked,
+                       struct mem_cgroup *mem_cont)
 {
        int referenced = 0;
 
@@ -401,14 +419,15 @@ int page_referenced(struct page *page, int is_locked)
 
        if (page_mapped(page) && page->mapping) {
                if (PageAnon(page))
-                       referenced += page_referenced_anon(page);
+                       referenced += page_referenced_anon(page, mem_cont);
                else if (is_locked)
-                       referenced += page_referenced_file(page);
+                       referenced += page_referenced_file(page, mem_cont);
                else if (TestSetPageLocked(page))
                        referenced++;
                else {
                        if (page->mapping)
-                               referenced += page_referenced_file(page);
+                               referenced +=
+                                       page_referenced_file(page, mem_cont);
                        unlock_page(page);
                }
        }
@@ -554,8 +573,14 @@ void page_add_anon_rmap(struct page *page,
        VM_BUG_ON(address < vma->vm_start || address >= vma->vm_end);
        if (atomic_inc_and_test(&page->_mapcount))
                __page_set_anon_rmap(page, vma, address);
-       else
+       else {
                __page_check_anon_rmap(page, vma, address);
+               /*
+                * We unconditionally charged during prepare, we uncharge here
+                * This takes care of balancing the reference counts
+                */
+               mem_cgroup_uncharge_page(page);
+       }
 }
 
 /*
@@ -586,6 +611,12 @@ void page_add_file_rmap(struct page *page)
 {
        if (atomic_inc_and_test(&page->_mapcount))
                __inc_zone_page_state(page, NR_FILE_MAPPED);
+       else
+               /*
+                * We unconditionally charged during prepare, we uncharge here
+                * This takes care of balancing the reference counts
+                */
+               mem_cgroup_uncharge_page(page);
 }
 
 #ifdef CONFIG_DEBUG_VM
@@ -646,6 +677,8 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
                        page_clear_dirty(page);
                        set_page_dirty(page);
                }
+               mem_cgroup_uncharge_page(page);
+
                __dec_zone_page_state(page,
                                PageAnon(page) ? NR_ANON_PAGES : NR_FILE_MAPPED);
        }
index 0f246c44a5744ec5aac0930c7896923e96bcb215..85bed948fafc8aecb22daf1f68023b91080a30f4 100644 (file)
@@ -912,9 +912,13 @@ found:
        error = 1;
        if (!inode)
                goto out;
-       error = radix_tree_preload(GFP_KERNEL);
+       /* Precharge page while we can wait, compensate afterwards */
+       error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL);
        if (error)
                goto out;
+       error = radix_tree_preload(GFP_KERNEL);
+       if (error)
+               goto uncharge;
        error = 1;
 
        spin_lock(&info->lock);
@@ -947,6 +951,8 @@ found:
                shmem_swp_unmap(ptr);
        spin_unlock(&info->lock);
        radix_tree_preload_end();
+uncharge:
+       mem_cgroup_uncharge_page(page);
 out:
        unlock_page(page);
        page_cache_release(page);
@@ -1308,6 +1314,13 @@ repeat:
                        spin_unlock(&info->lock);
                        unlock_page(swappage);
                        page_cache_release(swappage);
+                       if (error == -ENOMEM) {
+                               /* allow reclaim from this memory cgroup */
+                               error = mem_cgroup_cache_charge(NULL,
+                                       current->mm, gfp & ~__GFP_HIGHMEM);
+                               if (error)
+                                       goto failed;
+                       }
                        goto repeat;
                }
        } else if (sgp == SGP_READ && !filepage) {
@@ -1353,6 +1366,17 @@ repeat:
                                goto failed;
                        }
 
+                       /* Precharge page while we can wait, compensate after */
+                       error = mem_cgroup_cache_charge(filepage, current->mm,
+                                                       gfp & ~__GFP_HIGHMEM);
+                       if (error) {
+                               page_cache_release(filepage);
+                               shmem_unacct_blocks(info->flags, 1);
+                               shmem_free_blocks(inode, 1);
+                               filepage = NULL;
+                               goto failed;
+                       }
+
                        spin_lock(&info->lock);
                        entry = shmem_swp_alloc(info, idx, sgp);
                        if (IS_ERR(entry))
@@ -1364,6 +1388,7 @@ repeat:
                        if (error || swap.val || 0 != add_to_page_cache_lru(
                                        filepage, mapping, idx, GFP_NOWAIT)) {
                                spin_unlock(&info->lock);
+                               mem_cgroup_uncharge_page(filepage);
                                page_cache_release(filepage);
                                shmem_unacct_blocks(info->flags, 1);
                                shmem_free_blocks(inode, 1);
@@ -1372,6 +1397,7 @@ repeat:
                                        goto failed;
                                goto repeat;
                        }
+                       mem_cgroup_uncharge_page(filepage);
                        info->flags |= SHMEM_PAGEIN;
                }
 
index 57b7e25a939c41112d20f4f08f22517fcb112580..710a20bb9749cc9c9397e85bb59643dc38c27698 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -29,6 +29,7 @@
 #include <linux/cpu.h>
 #include <linux/notifier.h>
 #include <linux/backing-dev.h>
+#include <linux/memcontrol.h>
 
 /* How many pages do we try to swap or page in/out together? */
 int page_cluster;
@@ -175,6 +176,7 @@ void activate_page(struct page *page)
                SetPageActive(page);
                add_page_to_active_list(zone, page);
                __count_vm_event(PGACTIVATE);
+               mem_cgroup_move_lists(page_get_page_cgroup(page), true);
        }
        spin_unlock_irq(&zone->lru_lock);
 }
index eade24da9310d4cc4e7499e5580d52fbb929701c..02ccab5ad9d9f2fdebfb525ed6a1b653266dc642 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mutex.h>
 #include <linux/capability.h>
 #include <linux/syscalls.h>
+#include <linux/memcontrol.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -511,11 +512,16 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
 {
        spinlock_t *ptl;
        pte_t *pte;
-       int found = 1;
+       int ret = 1;
+
+       if (mem_cgroup_charge(page, vma->vm_mm, GFP_KERNEL))
+               ret = -ENOMEM;
 
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) {
-               found = 0;
+               if (ret > 0)
+                       mem_cgroup_uncharge_page(page);
+               ret = 0;
                goto out;
        }
 
@@ -532,7 +538,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
        activate_page(page);
 out:
        pte_unmap_unlock(pte, ptl);
-       return found;
+       return ret;
 }
 
 static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
@@ -541,7 +547,7 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 {
        pte_t swp_pte = swp_entry_to_pte(entry);
        pte_t *pte;
-       int found = 0;
+       int ret = 0;
 
        /*
         * We don't actually need pte lock while scanning for swp_pte: since
@@ -560,15 +566,15 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                 */
                if (unlikely(pte_same(*pte, swp_pte))) {
                        pte_unmap(pte);
-                       found = unuse_pte(vma, pmd, addr, entry, page);
-                       if (found)
+                       ret = unuse_pte(vma, pmd, addr, entry, page);
+                       if (ret)
                                goto out;
                        pte = pte_offset_map(pmd, addr);
                }
        } while (pte++, addr += PAGE_SIZE, addr != end);
        pte_unmap(pte - 1);
 out:
-       return found;
+       return ret;
 }
 
 static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud,
@@ -577,14 +583,16 @@ static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud,
 {
        pmd_t *pmd;
        unsigned long next;
+       int ret;
 
        pmd = pmd_offset(pud, addr);
        do {
                next = pmd_addr_end(addr, end);
                if (pmd_none_or_clear_bad(pmd))
                        continue;
-               if (unuse_pte_range(vma, pmd, addr, next, entry, page))
-                       return 1;
+               ret = unuse_pte_range(vma, pmd, addr, next, entry, page);
+               if (ret)
+                       return ret;
        } while (pmd++, addr = next, addr != end);
        return 0;
 }
@@ -595,14 +603,16 @@ static inline int unuse_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
 {
        pud_t *pud;
        unsigned long next;
+       int ret;
 
        pud = pud_offset(pgd, addr);
        do {
                next = pud_addr_end(addr, end);
                if (pud_none_or_clear_bad(pud))
                        continue;
-               if (unuse_pmd_range(vma, pud, addr, next, entry, page))
-                       return 1;
+               ret = unuse_pmd_range(vma, pud, addr, next, entry, page);
+               if (ret)
+                       return ret;
        } while (pud++, addr = next, addr != end);
        return 0;
 }
@@ -612,6 +622,7 @@ static int unuse_vma(struct vm_area_struct *vma,
 {
        pgd_t *pgd;
        unsigned long addr, end, next;
+       int ret;
 
        if (page->mapping) {
                addr = page_address_in_vma(page, vma);
@@ -629,8 +640,9 @@ static int unuse_vma(struct vm_area_struct *vma,
                next = pgd_addr_end(addr, end);
                if (pgd_none_or_clear_bad(pgd))
                        continue;
-               if (unuse_pud_range(vma, pgd, addr, next, entry, page))
-                       return 1;
+               ret = unuse_pud_range(vma, pgd, addr, next, entry, page);
+               if (ret)
+                       return ret;
        } while (pgd++, addr = next, addr != end);
        return 0;
 }
@@ -639,6 +651,7 @@ static int unuse_mm(struct mm_struct *mm,
                                swp_entry_t entry, struct page *page)
 {
        struct vm_area_struct *vma;
+       int ret = 0;
 
        if (!down_read_trylock(&mm->mmap_sem)) {
                /*
@@ -651,15 +664,11 @@ static int unuse_mm(struct mm_struct *mm,
                lock_page(page);
        }
        for (vma = mm->mmap; vma; vma = vma->vm_next) {
-               if (vma->anon_vma && unuse_vma(vma, entry, page))
+               if (vma->anon_vma && (ret = unuse_vma(vma, entry, page)))
                        break;
        }
        up_read(&mm->mmap_sem);
-       /*
-        * Currently unuse_mm cannot fail, but leave error handling
-        * at call sites for now, since we change it from time to time.
-        */
-       return 0;
+       return (ret < 0)? ret: 0;
 }
 
 /*
index e5a9597e3bbc7aad2ed7af943528aa164eb4aa36..a26dabd62fed40c8ec7832dc4656feaf7d3909f9 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
+#include <linux/memcontrol.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -68,6 +69,22 @@ struct scan_control {
        int all_unreclaimable;
 
        int order;
+
+       /*
+        * Pages that have (or should have) IO pending.  If we run into
+        * a lot of these, we're better off waiting a little for IO to
+        * finish rather than scanning more pages in the VM.
+        */
+       int nr_io_pages;
+
+       /* Which cgroup do we reclaim from */
+       struct mem_cgroup *mem_cgroup;
+
+       /* Pluggable isolate pages callback */
+       unsigned long (*isolate_pages)(unsigned long nr, struct list_head *dst,
+                       unsigned long *scanned, int order, int mode,
+                       struct zone *z, struct mem_cgroup *mem_cont,
+                       int active);
 };
 
 #define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
@@ -109,6 +126,12 @@ long vm_total_pages;       /* The total number of pages which the VM controls */
 static LIST_HEAD(shrinker_list);
 static DECLARE_RWSEM(shrinker_rwsem);
 
+#ifdef CONFIG_CGROUP_MEM_CONT
+#define scan_global_lru(sc)    (!(sc)->mem_cgroup)
+#else
+#define scan_global_lru(sc)    (1)
+#endif
+
 /*
  * Add a shrinker callback to be called from the vm
  */
@@ -489,11 +512,13 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                         */
                        if (sync_writeback == PAGEOUT_IO_SYNC && may_enter_fs)
                                wait_on_page_writeback(page);
-                       else
+                       else {
+                               sc->nr_io_pages++;
                                goto keep_locked;
+                       }
                }
 
-               referenced = page_referenced(page, 1);
+               referenced = page_referenced(page, 1, sc->mem_cgroup);
                /* In active use or really unfreeable?  Activate it. */
                if (sc->order <= PAGE_ALLOC_COSTLY_ORDER &&
                                        referenced && page_mapping_inuse(page))
@@ -529,8 +554,10 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                if (PageDirty(page)) {
                        if (sc->order <= PAGE_ALLOC_COSTLY_ORDER && referenced)
                                goto keep_locked;
-                       if (!may_enter_fs)
+                       if (!may_enter_fs) {
+                               sc->nr_io_pages++;
                                goto keep_locked;
+                       }
                        if (!sc->may_writepage)
                                goto keep_locked;
 
@@ -541,8 +568,10 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        case PAGE_ACTIVATE:
                                goto activate_locked;
                        case PAGE_SUCCESS:
-                               if (PageWriteback(page) || PageDirty(page))
+                               if (PageWriteback(page) || PageDirty(page)) {
+                                       sc->nr_io_pages++;
                                        goto keep;
+                               }
                                /*
                                 * A synchronous write - probably a ramdisk.  Go
                                 * ahead and try to reclaim the page.
@@ -626,7 +655,7 @@ keep:
  *
  * returns 0 on success, -ve errno on failure.
  */
-static int __isolate_lru_page(struct page *page, int mode)
+int __isolate_lru_page(struct page *page, int mode)
 {
        int ret = -EINVAL;
 
@@ -760,6 +789,21 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
        return nr_taken;
 }
 
+static unsigned long isolate_pages_global(unsigned long nr,
+                                       struct list_head *dst,
+                                       unsigned long *scanned, int order,
+                                       int mode, struct zone *z,
+                                       struct mem_cgroup *mem_cont,
+                                       int active)
+{
+       if (active)
+               return isolate_lru_pages(nr, &z->active_list, dst,
+                                               scanned, order, mode);
+       else
+               return isolate_lru_pages(nr, &z->inactive_list, dst,
+                                               scanned, order, mode);
+}
+
 /*
  * clear_active_flags() is a helper for shrink_active_list(), clearing
  * any active bits from the pages in the list.
@@ -801,18 +845,19 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                unsigned long nr_freed;
                unsigned long nr_active;
 
-               nr_taken = isolate_lru_pages(sc->swap_cluster_max,
-                            &zone->inactive_list,
+               nr_taken = sc->isolate_pages(sc->swap_cluster_max,
                             &page_list, &nr_scan, sc->order,
                             (sc->order > PAGE_ALLOC_COSTLY_ORDER)?
-                                            ISOLATE_BOTH : ISOLATE_INACTIVE);
+                                            ISOLATE_BOTH : ISOLATE_INACTIVE,
+                               zone, sc->mem_cgroup, 0);
                nr_active = clear_active_flags(&page_list);
                __count_vm_events(PGDEACTIVATE, nr_active);
 
                __mod_zone_page_state(zone, NR_ACTIVE, -nr_active);
                __mod_zone_page_state(zone, NR_INACTIVE,
                                                -(nr_taken - nr_active));
-               zone->pages_scanned += nr_scan;
+               if (scan_global_lru(sc))
+                       zone->pages_scanned += nr_scan;
                spin_unlock_irq(&zone->lru_lock);
 
                nr_scanned += nr_scan;
@@ -844,8 +889,9 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                if (current_is_kswapd()) {
                        __count_zone_vm_events(PGSCAN_KSWAPD, zone, nr_scan);
                        __count_vm_events(KSWAPD_STEAL, nr_freed);
-               } else
+               } else if (scan_global_lru(sc))
                        __count_zone_vm_events(PGSCAN_DIRECT, zone, nr_scan);
+
                __count_zone_vm_events(PGSTEAL, zone, nr_freed);
 
                if (nr_taken == 0)
@@ -898,6 +944,113 @@ static inline int zone_is_near_oom(struct zone *zone)
                                + zone_page_state(zone, NR_INACTIVE))*3;
 }
 
+/*
+ * Determine we should try to reclaim mapped pages.
+ * This is called only when sc->mem_cgroup is NULL.
+ */
+static int calc_reclaim_mapped(struct scan_control *sc, struct zone *zone,
+                               int priority)
+{
+       long mapped_ratio;
+       long distress;
+       long swap_tendency;
+       long imbalance;
+       int reclaim_mapped = 0;
+       int prev_priority;
+
+       if (scan_global_lru(sc) && zone_is_near_oom(zone))
+               return 1;
+       /*
+        * `distress' is a measure of how much trouble we're having
+        * reclaiming pages.  0 -> no problems.  100 -> great trouble.
+        */
+       if (scan_global_lru(sc))
+               prev_priority = zone->prev_priority;
+       else
+               prev_priority = mem_cgroup_get_reclaim_priority(sc->mem_cgroup);
+
+       distress = 100 >> min(prev_priority, priority);
+
+       /*
+        * The point of this algorithm is to decide when to start
+        * reclaiming mapped memory instead of just pagecache.  Work out
+        * how much memory
+        * is mapped.
+        */
+       if (scan_global_lru(sc))
+               mapped_ratio = ((global_page_state(NR_FILE_MAPPED) +
+                               global_page_state(NR_ANON_PAGES)) * 100) /
+                                       vm_total_pages;
+       else
+               mapped_ratio = mem_cgroup_calc_mapped_ratio(sc->mem_cgroup);
+
+       /*
+        * Now decide how much we really want to unmap some pages.  The
+        * mapped ratio is downgraded - just because there's a lot of
+        * mapped memory doesn't necessarily mean that page reclaim
+        * isn't succeeding.
+        *
+        * The distress ratio is important - we don't want to start
+        * going oom.
+        *
+        * A 100% value of vm_swappiness overrides this algorithm
+        * altogether.
+        */
+       swap_tendency = mapped_ratio / 2 + distress + sc->swappiness;
+
+       /*
+        * If there's huge imbalance between active and inactive
+        * (think active 100 times larger than inactive) we should
+        * become more permissive, or the system will take too much
+        * cpu before it start swapping during memory pressure.
+        * Distress is about avoiding early-oom, this is about
+        * making swappiness graceful despite setting it to low
+        * values.
+        *
+        * Avoid div by zero with nr_inactive+1, and max resulting
+        * value is vm_total_pages.
+        */
+       if (scan_global_lru(sc)) {
+               imbalance  = zone_page_state(zone, NR_ACTIVE);
+               imbalance /= zone_page_state(zone, NR_INACTIVE) + 1;
+       } else
+               imbalance = mem_cgroup_reclaim_imbalance(sc->mem_cgroup);
+
+       /*
+        * Reduce the effect of imbalance if swappiness is low,
+        * this means for a swappiness very low, the imbalance
+        * must be much higher than 100 for this logic to make
+        * the difference.
+        *
+        * Max temporary value is vm_total_pages*100.
+        */
+       imbalance *= (vm_swappiness + 1);
+       imbalance /= 100;
+
+       /*
+        * If not much of the ram is mapped, makes the imbalance
+        * less relevant, it's high priority we refill the inactive
+        * list with mapped pages only in presence of high ratio of
+        * mapped pages.
+        *
+        * Max temporary value is vm_total_pages*100.
+        */
+       imbalance *= mapped_ratio;
+       imbalance /= 100;
+
+       /* apply imbalance feedback to swap_tendency */
+       swap_tendency += imbalance;
+
+       /*
+        * Now use this metric to decide whether to start moving mapped
+        * memory onto the inactive list.
+        */
+       if (swap_tendency >= 100)
+               reclaim_mapped = 1;
+
+       return reclaim_mapped;
+}
+
 /*
  * This moves pages from the active list to the inactive list.
  *
@@ -915,6 +1068,8 @@ static inline int zone_is_near_oom(struct zone *zone)
  * The downside is that we have to touch page->_count against each page.
  * But we had to alter page->flags anyway.
  */
+
+
 static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
                                struct scan_control *sc, int priority)
 {
@@ -928,99 +1083,21 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
        struct pagevec pvec;
        int reclaim_mapped = 0;
 
-       if (sc->may_swap) {
-               long mapped_ratio;
-               long distress;
-               long swap_tendency;
-               long imbalance;
-
-               if (zone_is_near_oom(zone))
-                       goto force_reclaim_mapped;
-
-               /*
-                * `distress' is a measure of how much trouble we're having
-                * reclaiming pages.  0 -> no problems.  100 -> great trouble.
-                */
-               distress = 100 >> min(zone->prev_priority, priority);
-
-               /*
-                * The point of this algorithm is to decide when to start
-                * reclaiming mapped memory instead of just pagecache.  Work out
-                * how much memory
-                * is mapped.
-                */
-               mapped_ratio = ((global_page_state(NR_FILE_MAPPED) +
-                               global_page_state(NR_ANON_PAGES)) * 100) /
-                                       vm_total_pages;
-
-               /*
-                * Now decide how much we really want to unmap some pages.  The
-                * mapped ratio is downgraded - just because there's a lot of
-                * mapped memory doesn't necessarily mean that page reclaim
-                * isn't succeeding.
-                *
-                * The distress ratio is important - we don't want to start
-                * going oom.
-                *
-                * A 100% value of vm_swappiness overrides this algorithm
-                * altogether.
-                */
-               swap_tendency = mapped_ratio / 2 + distress + sc->swappiness;
-
-               /*
-                * If there's huge imbalance between active and inactive
-                * (think active 100 times larger than inactive) we should
-                * become more permissive, or the system will take too much
-                * cpu before it start swapping during memory pressure.
-                * Distress is about avoiding early-oom, this is about
-                * making swappiness graceful despite setting it to low
-                * values.
-                *
-                * Avoid div by zero with nr_inactive+1, and max resulting
-                * value is vm_total_pages.
-                */
-               imbalance  = zone_page_state(zone, NR_ACTIVE);
-               imbalance /= zone_page_state(zone, NR_INACTIVE) + 1;
-
-               /*
-                * Reduce the effect of imbalance if swappiness is low,
-                * this means for a swappiness very low, the imbalance
-                * must be much higher than 100 for this logic to make
-                * the difference.
-                *
-                * Max temporary value is vm_total_pages*100.
-                */
-               imbalance *= (vm_swappiness + 1);
-               imbalance /= 100;
-
-               /*
-                * If not much of the ram is mapped, makes the imbalance
-                * less relevant, it's high priority we refill the inactive
-                * list with mapped pages only in presence of high ratio of
-                * mapped pages.
-                *
-                * Max temporary value is vm_total_pages*100.
-                */
-               imbalance *= mapped_ratio;
-               imbalance /= 100;
-
-               /* apply imbalance feedback to swap_tendency */
-               swap_tendency += imbalance;
-
-               /*
-                * Now use this metric to decide whether to start moving mapped
-                * memory onto the inactive list.
-                */
-               if (swap_tendency >= 100)
-force_reclaim_mapped:
-                       reclaim_mapped = 1;
-       }
+       if (sc->may_swap)
+               reclaim_mapped = calc_reclaim_mapped(sc, zone, priority);
 
        lru_add_drain();
        spin_lock_irq(&zone->lru_lock);
-       pgmoved = isolate_lru_pages(nr_pages, &zone->active_list,
-                           &l_hold, &pgscanned, sc->order, ISOLATE_ACTIVE);
-       zone->pages_scanned += pgscanned;
+       pgmoved = sc->isolate_pages(nr_pages, &l_hold, &pgscanned, sc->order,
+                                       ISOLATE_ACTIVE, zone,
+                                       sc->mem_cgroup, 1);
+       /*
+        * zone->pages_scanned is used for detect zone's oom
+        * mem_cgroup remembers nr_scan by itself.
+        */
+       if (scan_global_lru(sc))
+               zone->pages_scanned += pgscanned;
+
        __mod_zone_page_state(zone, NR_ACTIVE, -pgmoved);
        spin_unlock_irq(&zone->lru_lock);
 
@@ -1031,7 +1108,7 @@ force_reclaim_mapped:
                if (page_mapped(page)) {
                        if (!reclaim_mapped ||
                            (total_swap_pages == 0 && PageAnon(page)) ||
-                           page_referenced(page, 0)) {
+                           page_referenced(page, 0, sc->mem_cgroup)) {
                                list_add(&page->lru, &l_active);
                                continue;
                        }
@@ -1051,6 +1128,7 @@ force_reclaim_mapped:
                ClearPageActive(page);
 
                list_move(&page->lru, &zone->inactive_list);
+               mem_cgroup_move_lists(page_get_page_cgroup(page), false);
                pgmoved++;
                if (!pagevec_add(&pvec, page)) {
                        __mod_zone_page_state(zone, NR_INACTIVE, pgmoved);
@@ -1079,6 +1157,7 @@ force_reclaim_mapped:
                SetPageLRU(page);
                VM_BUG_ON(!PageActive(page));
                list_move(&page->lru, &zone->active_list);
+               mem_cgroup_move_lists(page_get_page_cgroup(page), true);
                pgmoved++;
                if (!pagevec_add(&pvec, page)) {
                        __mod_zone_page_state(zone, NR_ACTIVE, pgmoved);
@@ -1108,25 +1187,39 @@ static unsigned long shrink_zone(int priority, struct zone *zone,
        unsigned long nr_to_scan;
        unsigned long nr_reclaimed = 0;
 
-       /*
-        * Add one to `nr_to_scan' just to make sure that the kernel will
-        * slowly sift through the active list.
-        */
-       zone->nr_scan_active +=
-               (zone_page_state(zone, NR_ACTIVE) >> priority) + 1;
-       nr_active = zone->nr_scan_active;
-       if (nr_active >= sc->swap_cluster_max)
-               zone->nr_scan_active = 0;
-       else
-               nr_active = 0;
+       if (scan_global_lru(sc)) {
+               /*
+                * Add one to nr_to_scan just to make sure that the kernel
+                * will slowly sift through the active list.
+                */
+               zone->nr_scan_active +=
+                       (zone_page_state(zone, NR_ACTIVE) >> priority) + 1;
+               nr_active = zone->nr_scan_active;
+               zone->nr_scan_inactive +=
+                       (zone_page_state(zone, NR_INACTIVE) >> priority) + 1;
+               nr_inactive = zone->nr_scan_inactive;
+               if (nr_inactive >= sc->swap_cluster_max)
+                       zone->nr_scan_inactive = 0;
+               else
+                       nr_inactive = 0;
+
+               if (nr_active >= sc->swap_cluster_max)
+                       zone->nr_scan_active = 0;
+               else
+                       nr_active = 0;
+       } else {
+               /*
+                * This reclaim occurs not because zone memory shortage but
+                * because memory controller hits its limit.
+                * Then, don't modify zone reclaim related data.
+                */
+               nr_active = mem_cgroup_calc_reclaim_active(sc->mem_cgroup,
+                                       zone, priority);
+
+               nr_inactive = mem_cgroup_calc_reclaim_inactive(sc->mem_cgroup,
+                                       zone, priority);
+       }
 
-       zone->nr_scan_inactive +=
-               (zone_page_state(zone, NR_INACTIVE) >> priority) + 1;
-       nr_inactive = zone->nr_scan_inactive;
-       if (nr_inactive >= sc->swap_cluster_max)
-               zone->nr_scan_inactive = 0;
-       else
-               nr_inactive = 0;
 
        while (nr_active || nr_inactive) {
                if (nr_active) {
@@ -1171,25 +1264,39 @@ static unsigned long shrink_zones(int priority, struct zone **zones,
        unsigned long nr_reclaimed = 0;
        int i;
 
+
        sc->all_unreclaimable = 1;
        for (i = 0; zones[i] != NULL; i++) {
                struct zone *zone = zones[i];
 
                if (!populated_zone(zone))
                        continue;
+               /*
+                * Take care memory controller reclaiming has small influence
+                * to global LRU.
+                */
+               if (scan_global_lru(sc)) {
+                       if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
+                               continue;
+                       note_zone_scanning_priority(zone, priority);
 
-               if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
-                       continue;
-
-               note_zone_scanning_priority(zone, priority);
-
-               if (zone_is_all_unreclaimable(zone) && priority != DEF_PRIORITY)
-                       continue;       /* Let kswapd poll it */
-
-               sc->all_unreclaimable = 0;
+                       if (zone_is_all_unreclaimable(zone) &&
+                                               priority != DEF_PRIORITY)
+                               continue;       /* Let kswapd poll it */
+                       sc->all_unreclaimable = 0;
+               } else {
+                       /*
+                        * Ignore cpuset limitation here. We just want to reduce
+                        * # of used pages by us regardless of memory shortage.
+                        */
+                       sc->all_unreclaimable = 0;
+                       mem_cgroup_note_reclaim_priority(sc->mem_cgroup,
+                                                       priority);
+               }
 
                nr_reclaimed += shrink_zone(priority, zone, sc);
        }
+
        return nr_reclaimed;
 }
  
@@ -1206,7 +1313,8 @@ static unsigned long shrink_zones(int priority, struct zone **zones,
  * holds filesystem locks which prevent writeout this might not work, and the
  * allocation attempt will fail.
  */
-unsigned long try_to_free_pages(struct zone **zones, int order, gfp_t gfp_mask)
+static unsigned long do_try_to_free_pages(struct zone **zones, gfp_t gfp_mask,
+                                         struct scan_control *sc)
 {
        int priority;
        int ret = 0;
@@ -1215,39 +1323,43 @@ unsigned long try_to_free_pages(struct zone **zones, int order, gfp_t gfp_mask)
        struct reclaim_state *reclaim_state = current->reclaim_state;
        unsigned long lru_pages = 0;
        int i;
-       struct scan_control sc = {
-               .gfp_mask = gfp_mask,
-               .may_writepage = !laptop_mode,
-               .swap_cluster_max = SWAP_CLUSTER_MAX,
-               .may_swap = 1,
-               .swappiness = vm_swappiness,
-               .order = order,
-       };
-
-       count_vm_event(ALLOCSTALL);
 
-       for (i = 0; zones[i] != NULL; i++) {
-               struct zone *zone = zones[i];
+       if (scan_global_lru(sc))
+               count_vm_event(ALLOCSTALL);
+       /*
+        * mem_cgroup will not do shrink_slab.
+        */
+       if (scan_global_lru(sc)) {
+               for (i = 0; zones[i] != NULL; i++) {
+                       struct zone *zone = zones[i];
 
-               if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
-                       continue;
+                       if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
+                               continue;
 
-               lru_pages += zone_page_state(zone, NR_ACTIVE)
-                               + zone_page_state(zone, NR_INACTIVE);
+                       lru_pages += zone_page_state(zone, NR_ACTIVE)
+                                       + zone_page_state(zone, NR_INACTIVE);
+               }
        }
 
        for (priority = DEF_PRIORITY; priority >= 0; priority--) {
-               sc.nr_scanned = 0;
+               sc->nr_scanned = 0;
+               sc->nr_io_pages = 0;
                if (!priority)
                        disable_swap_token();
-               nr_reclaimed += shrink_zones(priority, zones, &sc);
-               shrink_slab(sc.nr_scanned, gfp_mask, lru_pages);
-               if (reclaim_state) {
-                       nr_reclaimed += reclaim_state->reclaimed_slab;
-                       reclaim_state->reclaimed_slab = 0;
+               nr_reclaimed += shrink_zones(priority, zones, sc);
+               /*
+                * Don't shrink slabs when reclaiming memory from
+                * over limit cgroups
+                */
+               if (scan_global_lru(sc)) {
+                       shrink_slab(sc->nr_scanned, gfp_mask, lru_pages);
+                       if (reclaim_state) {
+                               nr_reclaimed += reclaim_state->reclaimed_slab;
+                               reclaim_state->reclaimed_slab = 0;
+                       }
                }
-               total_scanned += sc.nr_scanned;
-               if (nr_reclaimed >= sc.swap_cluster_max) {
+               total_scanned += sc->nr_scanned;
+               if (nr_reclaimed >= sc->swap_cluster_max) {
                        ret = 1;
                        goto out;
                }
@@ -1259,18 +1371,19 @@ unsigned long try_to_free_pages(struct zone **zones, int order, gfp_t gfp_mask)
                 * that's undesirable in laptop mode, where we *want* lumpy
                 * writeout.  So in laptop mode, write out the whole world.
                 */
-               if (total_scanned > sc.swap_cluster_max +
-                                       sc.swap_cluster_max / 2) {
+               if (total_scanned > sc->swap_cluster_max +
+                                       sc->swap_cluster_max / 2) {
                        wakeup_pdflush(laptop_mode ? 0 : total_scanned);
-                       sc.may_writepage = 1;
+                       sc->may_writepage = 1;
                }
 
                /* Take a nap, wait for some writeback to complete */
-               if (sc.nr_scanned && priority < DEF_PRIORITY - 2)
+               if (sc->nr_scanned && priority < DEF_PRIORITY - 2 &&
+                               sc->nr_io_pages > sc->swap_cluster_max)
                        congestion_wait(WRITE, HZ/10);
        }
        /* top priority shrink_caches still had more to do? don't OOM, then */
-       if (!sc.all_unreclaimable)
+       if (!sc->all_unreclaimable && scan_global_lru(sc))
                ret = 1;
 out:
        /*
@@ -1282,17 +1395,63 @@ out:
         */
        if (priority < 0)
                priority = 0;
-       for (i = 0; zones[i] != NULL; i++) {
-               struct zone *zone = zones[i];
 
-               if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
-                       continue;
+       if (scan_global_lru(sc)) {
+               for (i = 0; zones[i] != NULL; i++) {
+                       struct zone *zone = zones[i];
+
+                       if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
+                               continue;
+
+                       zone->prev_priority = priority;
+               }
+       } else
+               mem_cgroup_record_reclaim_priority(sc->mem_cgroup, priority);
 
-               zone->prev_priority = priority;
-       }
        return ret;
 }
 
+unsigned long try_to_free_pages(struct zone **zones, int order, gfp_t gfp_mask)
+{
+       struct scan_control sc = {
+               .gfp_mask = gfp_mask,
+               .may_writepage = !laptop_mode,
+               .swap_cluster_max = SWAP_CLUSTER_MAX,
+               .may_swap = 1,
+               .swappiness = vm_swappiness,
+               .order = order,
+               .mem_cgroup = NULL,
+               .isolate_pages = isolate_pages_global,
+       };
+
+       return do_try_to_free_pages(zones, gfp_mask, &sc);
+}
+
+#ifdef CONFIG_CGROUP_MEM_CONT
+
+unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
+                                               gfp_t gfp_mask)
+{
+       struct scan_control sc = {
+               .gfp_mask = gfp_mask,
+               .may_writepage = !laptop_mode,
+               .may_swap = 1,
+               .swap_cluster_max = SWAP_CLUSTER_MAX,
+               .swappiness = vm_swappiness,
+               .order = 0,
+               .mem_cgroup = mem_cont,
+               .isolate_pages = mem_cgroup_isolate_pages,
+       };
+       struct zone **zones;
+       int target_zone = gfp_zone(GFP_HIGHUSER_MOVABLE);
+
+       zones = NODE_DATA(numa_node_id())->node_zonelists[target_zone].zones;
+       if (do_try_to_free_pages(zones, sc.gfp_mask, &sc))
+               return 1;
+       return 0;
+}
+#endif
+
 /*
  * For kswapd, balance_pgdat() will work across all this node's zones until
  * they are all at pages_high.
@@ -1328,6 +1487,8 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
                .swap_cluster_max = SWAP_CLUSTER_MAX,
                .swappiness = vm_swappiness,
                .order = order,
+               .mem_cgroup = NULL,
+               .isolate_pages = isolate_pages_global,
        };
        /*
         * temp_priority is used to remember the scanning priority at which
@@ -1352,6 +1513,7 @@ loop_again:
                if (!priority)
                        disable_swap_token();
 
+               sc.nr_io_pages = 0;
                all_zones_ok = 1;
 
                /*
@@ -1444,7 +1606,8 @@ loop_again:
                 * OK, kswapd is getting into trouble.  Take a nap, then take
                 * another pass across the zones.
                 */
-               if (total_scanned && priority < DEF_PRIORITY - 2)
+               if (total_scanned && priority < DEF_PRIORITY - 2 &&
+                                       sc.nr_io_pages > sc.swap_cluster_max)
                        congestion_wait(WRITE, HZ/10);
 
                /*
@@ -1649,6 +1812,7 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
                .swap_cluster_max = nr_pages,
                .may_writepage = 1,
                .swappiness = vm_swappiness,
+               .isolate_pages = isolate_pages_global,
        };
 
        current->reclaim_state = &reclaim_state;
@@ -1834,6 +1998,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
                                        SWAP_CLUSTER_MAX),
                .gfp_mask = gfp_mask,
                .swappiness = vm_swappiness,
+               .isolate_pages = isolate_pages_global,
        };
        unsigned long slab_reclaimable;
 
index d3abb246ccab41af3b237945f0fd520e96e451fe..8a105110189830f5b527047ac4e299462f038710 100644 (file)
@@ -4,7 +4,6 @@ obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o
 
 9pnet-objs := \
        mod.o \
-       mux.o \
        client.o \
        conv.o \
        error.o \
index af9199364049becdb5fb3442e43581e485173cd9..84e087e2414606ce56a3903eaae048ec1a2066ef 100644 (file)
@@ -3,6 +3,7 @@
  *
  * 9P Client
  *
+ *  Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
  *  Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -25,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/poll.h>
 #include <linux/idr.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <net/9p/9p.h>
 #include <linux/parser.h>
 #include <net/9p/transport.h>
-#include <net/9p/conn.h>
 #include <net/9p/client.h>
 
 static struct p9_fid *p9_fid_create(struct p9_client *clnt);
 static void p9_fid_destroy(struct p9_fid *fid);
 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
 
-struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
-                                                                  int dotu)
+/*
+  * Client Option Parsing (code inspired by NFS code)
+  *  - a little lazy - parse all client options
+  */
+
+enum {
+       Opt_msize,
+       Opt_trans,
+       Opt_legacy,
+       Opt_err,
+};
+
+static match_table_t tokens = {
+       {Opt_msize, "msize=%u"},
+       {Opt_legacy, "noextend"},
+       {Opt_trans, "trans=%s"},
+       {Opt_err, NULL},
+};
+
+/**
+ * v9fs_parse_options - parse mount options into session structure
+ * @options: options string passed from mount
+ * @v9ses: existing v9fs session information
+ *
+ */
+
+static void parse_opts(char *options, struct p9_client *clnt)
+{
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+       int ret;
+
+       clnt->trans_mod = v9fs_default_trans();
+       clnt->dotu = 1;
+       clnt->msize = 8192;
+
+       if (!options)
+               return;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
+                       continue;
+               token = match_token(p, tokens, args);
+               if (token < Opt_trans) {
+                       ret = match_int(&args[0], &option);
+                       if (ret < 0) {
+                               P9_DPRINTK(P9_DEBUG_ERROR,
+                                       "integer field, but no integer?\n");
+                               continue;
+                       }
+               }
+               switch (token) {
+               case Opt_msize:
+                       clnt->msize = option;
+                       break;
+               case Opt_trans:
+                       clnt->trans_mod = v9fs_match_trans(&args[0]);
+                       break;
+               case Opt_legacy:
+                       clnt->dotu = 0;
+                       break;
+               default:
+                       continue;
+               }
+       }
+}
+
+
+/**
+ * p9_client_rpc - sends 9P request and waits until a response is available.
+ *      The function can be interrupted.
+ * @c: client data
+ * @tc: request to be sent
+ * @rc: pointer where a pointer to the response is stored
+ */
+int
+p9_client_rpc(struct p9_client *c, struct p9_fcall *tc,
+       struct p9_fcall **rc)
+{
+       return c->trans->rpc(c->trans, tc, rc);
+}
+
+struct p9_client *p9_client_create(const char *dev_name, char *options)
 {
        int err, n;
        struct p9_client *clnt;
@@ -54,12 +138,7 @@ struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
        if (!clnt)
                return ERR_PTR(-ENOMEM);
 
-       P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
-               clnt, trans, msize, dotu);
        spin_lock_init(&clnt->lock);
-       clnt->trans = trans;
-       clnt->msize = msize;
-       clnt->dotu = dotu;
        INIT_LIST_HEAD(&clnt->fidlist);
        clnt->fidpool = p9_idpool_create();
        if (!clnt->fidpool) {
@@ -68,13 +147,29 @@ struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
                goto error;
        }
 
-       clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu);
-       if (IS_ERR(clnt->conn)) {
-               err = PTR_ERR(clnt->conn);
-               clnt->conn = NULL;
+       parse_opts(options, clnt);
+       if (clnt->trans_mod == NULL) {
+               err = -EPROTONOSUPPORT;
+               P9_DPRINTK(P9_DEBUG_ERROR,
+                               "No transport defined or default transport\n");
                goto error;
        }
 
+       P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
+               clnt, clnt->trans_mod, clnt->msize, clnt->dotu);
+
+
+       clnt->trans = clnt->trans_mod->create(dev_name, options, clnt->msize,
+                                                               clnt->dotu);
+       if (IS_ERR(clnt->trans)) {
+               err = PTR_ERR(clnt->trans);
+               clnt->trans = NULL;
+               goto error;
+       }
+
+       if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
+               clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
+
        tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
        if (IS_ERR(tc)) {
                err = PTR_ERR(tc);
@@ -82,7 +177,7 @@ struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
                goto error;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
        if (err)
                goto error;
 
@@ -117,10 +212,6 @@ void p9_client_destroy(struct p9_client *clnt)
        struct p9_fid *fid, *fidptr;
 
        P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
-       if (clnt->conn) {
-               p9_conn_destroy(clnt->conn);
-               clnt->conn = NULL;
-       }
 
        if (clnt->trans) {
                clnt->trans->close(clnt->trans);
@@ -142,7 +233,6 @@ void p9_client_disconnect(struct p9_client *clnt)
 {
        P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
        clnt->trans->status = Disconnected;
-       p9_conn_cancel(clnt->conn, -EIO);
 }
 EXPORT_SYMBOL(p9_client_disconnect);
 
@@ -174,7 +264,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
                goto error;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
        if (err)
                goto error;
 
@@ -219,7 +309,7 @@ struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
                goto error;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
        if (err)
                goto error;
 
@@ -270,7 +360,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
                goto error;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
        if (err) {
                if (rc && rc->id == P9_RWALK)
                        goto clunk_fid;
@@ -305,7 +395,7 @@ clunk_fid:
                goto error;
        }
 
-       p9_conn_rpc(clnt->conn, tc, &rc);
+       p9_client_rpc(clnt, tc, &rc);
 
 error:
        kfree(tc);
@@ -339,7 +429,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
                goto done;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
        if (err)
                goto done;
 
@@ -378,7 +468,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
                goto done;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
        if (err)
                goto done;
 
@@ -411,7 +501,7 @@ int p9_client_clunk(struct p9_fid *fid)
                goto done;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
        if (err)
                goto done;
 
@@ -443,7 +533,7 @@ int p9_client_remove(struct p9_fid *fid)
                goto done;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
        if (err)
                goto done;
 
@@ -485,7 +575,7 @@ int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
                        goto error;
                }
 
-               err = p9_conn_rpc(clnt->conn, tc, &rc);
+               err = p9_client_rpc(clnt, tc, &rc);
                if (err)
                        goto error;
 
@@ -542,7 +632,7 @@ int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
                        goto error;
                }
 
-               err = p9_conn_rpc(clnt->conn, tc, &rc);
+               err = p9_client_rpc(clnt, tc, &rc);
                if (err)
                        goto error;
 
@@ -596,7 +686,7 @@ p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
                        goto error;
                }
 
-               err = p9_conn_rpc(clnt->conn, tc, &rc);
+               err = p9_client_rpc(clnt, tc, &rc);
                if (err)
                        goto error;
 
@@ -660,7 +750,7 @@ p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
                        goto error;
                }
 
-               err = p9_conn_rpc(clnt->conn, tc, &rc);
+               err = p9_client_rpc(clnt, tc, &rc);
                if (err)
                        goto error;
 
@@ -731,7 +821,7 @@ struct p9_stat *p9_client_stat(struct p9_fid *fid)
                goto error;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
        if (err)
                goto error;
 
@@ -773,7 +863,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
                goto done;
        }
 
-       err = p9_conn_rpc(clnt->conn, tc, &rc);
+       err = p9_client_rpc(clnt, tc, &rc);
 
 done:
        kfree(tc);
@@ -830,7 +920,7 @@ struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
                                goto error;
                        }
 
-                       err = p9_conn_rpc(clnt->conn, tc, &rc);
+                       err = p9_client_rpc(clnt, tc, &rc);
                        if (err)
                                goto error;
 
@@ -901,16 +991,21 @@ static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
        memmove(ret, st, sizeof(struct p9_stat));
        p = ((char *) ret) + sizeof(struct p9_stat);
        memmove(p, st->name.str, st->name.len);
+       ret->name.str = p;
        p += st->name.len;
        memmove(p, st->uid.str, st->uid.len);
+       ret->uid.str = p;
        p += st->uid.len;
        memmove(p, st->gid.str, st->gid.len);
+       ret->gid.str = p;
        p += st->gid.len;
        memmove(p, st->muid.str, st->muid.len);
+       ret->muid.str = p;
        p += st->muid.len;
 
        if (dotu) {
                memmove(p, st->extension.str, st->extension.len);
+               ret->extension.str = p;
                p += st->extension.len;
        }
 
index b1ae8ec57d54e8e5dbcc277ebb4b0266bffa2c6e..40244fbd9b0d15d2f66eb70cc4ff8f5d0a1d9b59 100644 (file)
@@ -347,12 +347,12 @@ p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
 
        return ret;
 }
-
 #else
 int
 p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
 {
        return 0;
 }
-EXPORT_SYMBOL(p9_printfcall);
 #endif /* CONFIG_NET_9P_DEBUG */
+EXPORT_SYMBOL(p9_printfcall);
+
index 8f9763a9dc1296b54a2d889a6bae9402ccf6cd37..c285aab2af04ba78683e98f45175815f1aadbbab 100644 (file)
@@ -106,15 +106,10 @@ EXPORT_SYMBOL(v9fs_default_trans);
  */
 static int __init init_p9(void)
 {
-       int ret;
+       int ret = 0;
 
        p9_error_init();
        printk(KERN_INFO "Installing 9P2000 support\n");
-       ret = p9_mux_global_init();
-       if (ret) {
-               printk(KERN_WARNING "9p: starting mux failed\n");
-               return ret;
-       }
 
        return ret;
 }
@@ -126,7 +121,7 @@ static int __init init_p9(void)
 
 static void __exit exit_p9(void)
 {
-       p9_mux_global_exit();
+       printk(KERN_INFO "Unloading 9P2000 support\n");
 }
 
 module_init(init_p9)
diff --git a/net/9p/mux.c b/net/9p/mux.c
deleted file mode 100644 (file)
index c9f0805..0000000
+++ /dev/null
@@ -1,1060 +0,0 @@
-/*
- * net/9p/mux.c
- *
- * Protocol Multiplexer
- *
- *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2
- *  as published by the Free Software Foundation.
- *
- *  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:
- *  Free Software Foundation
- *  51 Franklin Street, Fifth Floor
- *  Boston, MA  02111-1301  USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/kthread.h>
-#include <linux/idr.h>
-#include <linux/mutex.h>
-#include <net/9p/9p.h>
-#include <linux/parser.h>
-#include <net/9p/transport.h>
-#include <net/9p/conn.h>
-
-#define ERREQFLUSH     1
-#define SCHED_TIMEOUT  10
-#define MAXPOLLWADDR   2
-
-enum {
-       Rworksched = 1,         /* read work scheduled or running */
-       Rpending = 2,           /* can read */
-       Wworksched = 4,         /* write work scheduled or running */
-       Wpending = 8,           /* can write */
-};
-
-enum {
-       None,
-       Flushing,
-       Flushed,
-};
-
-struct p9_mux_poll_task;
-
-struct p9_req {
-       spinlock_t lock; /* protect request structure */
-       int tag;
-       struct p9_fcall *tcall;
-       struct p9_fcall *rcall;
-       int err;
-       p9_conn_req_callback cb;
-       void *cba;
-       int flush;
-       struct list_head req_list;
-};
-
-struct p9_conn {
-       spinlock_t lock; /* protect lock structure */
-       struct list_head mux_list;
-       struct p9_mux_poll_task *poll_task;
-       int msize;
-       unsigned char *extended;
-       struct p9_trans *trans;
-       struct p9_idpool *tagpool;
-       int err;
-       wait_queue_head_t equeue;
-       struct list_head req_list;
-       struct list_head unsent_req_list;
-       struct p9_fcall *rcall;
-       int rpos;
-       char *rbuf;
-       int wpos;
-       int wsize;
-       char *wbuf;
-       wait_queue_t poll_wait[MAXPOLLWADDR];
-       wait_queue_head_t *poll_waddr[MAXPOLLWADDR];
-       poll_table pt;
-       struct work_struct rq;
-       struct work_struct wq;
-       unsigned long wsched;
-};
-
-struct p9_mux_poll_task {
-       struct task_struct *task;
-       struct list_head mux_list;
-       int muxnum;
-};
-
-struct p9_mux_rpc {
-       struct p9_conn *m;
-       int err;
-       struct p9_fcall *tcall;
-       struct p9_fcall *rcall;
-       wait_queue_head_t wqueue;
-};
-
-static int p9_poll_proc(void *);
-static void p9_read_work(struct work_struct *work);
-static void p9_write_work(struct work_struct *work);
-static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
-                         poll_table * p);
-static u16 p9_mux_get_tag(struct p9_conn *);
-static void p9_mux_put_tag(struct p9_conn *, u16);
-
-static DEFINE_MUTEX(p9_mux_task_lock);
-static struct workqueue_struct *p9_mux_wq;
-
-static int p9_mux_num;
-static int p9_mux_poll_task_num;
-static struct p9_mux_poll_task p9_mux_poll_tasks[100];
-
-int p9_mux_global_init(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
-               p9_mux_poll_tasks[i].task = NULL;
-
-       p9_mux_wq = create_workqueue("v9fs");
-       if (!p9_mux_wq) {
-               printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-void p9_mux_global_exit(void)
-{
-       destroy_workqueue(p9_mux_wq);
-}
-
-/**
- * p9_mux_calc_poll_procs - calculates the number of polling procs
- * based on the number of mounted v9fs filesystems.
- *
- * The current implementation returns sqrt of the number of mounts.
- */
-static int p9_mux_calc_poll_procs(int muxnum)
-{
-       int n;
-
-       if (p9_mux_poll_task_num)
-               n = muxnum / p9_mux_poll_task_num +
-                   (muxnum % p9_mux_poll_task_num ? 1 : 0);
-       else
-               n = 1;
-
-       if (n > ARRAY_SIZE(p9_mux_poll_tasks))
-               n = ARRAY_SIZE(p9_mux_poll_tasks);
-
-       return n;
-}
-
-static int p9_mux_poll_start(struct p9_conn *m)
-{
-       int i, n;
-       struct p9_mux_poll_task *vpt, *vptlast;
-       struct task_struct *pproc;
-
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num,
-               p9_mux_poll_task_num);
-       mutex_lock(&p9_mux_task_lock);
-
-       n = p9_mux_calc_poll_procs(p9_mux_num + 1);
-       if (n > p9_mux_poll_task_num) {
-               for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
-                       if (p9_mux_poll_tasks[i].task == NULL) {
-                               vpt = &p9_mux_poll_tasks[i];
-                               P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n",
-                                                                       vpt);
-                               pproc = kthread_create(p9_poll_proc, vpt,
-                                                               "v9fs-poll");
-
-                               if (!IS_ERR(pproc)) {
-                                       vpt->task = pproc;
-                                       INIT_LIST_HEAD(&vpt->mux_list);
-                                       vpt->muxnum = 0;
-                                       p9_mux_poll_task_num++;
-                                       wake_up_process(vpt->task);
-                               }
-                               break;
-                       }
-               }
-
-               if (i >= ARRAY_SIZE(p9_mux_poll_tasks))
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                                       "warning: no free poll slots\n");
-       }
-
-       n = (p9_mux_num + 1) / p9_mux_poll_task_num +
-           ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0);
-
-       vptlast = NULL;
-       for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
-               vpt = &p9_mux_poll_tasks[i];
-               if (vpt->task != NULL) {
-                       vptlast = vpt;
-                       if (vpt->muxnum < n) {
-                               P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
-                               list_add(&m->mux_list, &vpt->mux_list);
-                               vpt->muxnum++;
-                               m->poll_task = vpt;
-                               memset(&m->poll_waddr, 0,
-                                                       sizeof(m->poll_waddr));
-                               init_poll_funcptr(&m->pt, p9_pollwait);
-                               break;
-                       }
-               }
-       }
-
-       if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) {
-               if (vptlast == NULL) {
-                       mutex_unlock(&p9_mux_task_lock);
-                       return -ENOMEM;
-               }
-
-               P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
-               list_add(&m->mux_list, &vptlast->mux_list);
-               vptlast->muxnum++;
-               m->poll_task = vptlast;
-               memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
-               init_poll_funcptr(&m->pt, p9_pollwait);
-       }
-
-       p9_mux_num++;
-       mutex_unlock(&p9_mux_task_lock);
-
-       return 0;
-}
-
-static void p9_mux_poll_stop(struct p9_conn *m)
-{
-       int i;
-       struct p9_mux_poll_task *vpt;
-
-       mutex_lock(&p9_mux_task_lock);
-       vpt = m->poll_task;
-       list_del(&m->mux_list);
-       for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
-               if (m->poll_waddr[i] != NULL) {
-                       remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
-                       m->poll_waddr[i] = NULL;
-               }
-       }
-       vpt->muxnum--;
-       if (!vpt->muxnum) {
-               P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt);
-               kthread_stop(vpt->task);
-               vpt->task = NULL;
-               p9_mux_poll_task_num--;
-       }
-       p9_mux_num--;
-       mutex_unlock(&p9_mux_task_lock);
-}
-
-/**
- * p9_conn_create - allocate and initialize the per-session mux data
- * Creates the polling task if this is the first session.
- *
- * @trans - transport structure
- * @msize - maximum message size
- * @extended - pointer to the extended flag
- */
-struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize,
-                                   unsigned char *extended)
-{
-       int i, n;
-       struct p9_conn *m, *mtmp;
-
-       P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, msize);
-       m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL);
-       if (!m)
-               return ERR_PTR(-ENOMEM);
-
-       spin_lock_init(&m->lock);
-       INIT_LIST_HEAD(&m->mux_list);
-       m->msize = msize;
-       m->extended = extended;
-       m->trans = trans;
-       m->tagpool = p9_idpool_create();
-       if (IS_ERR(m->tagpool)) {
-               mtmp = ERR_PTR(-ENOMEM);
-               kfree(m);
-               return mtmp;
-       }
-
-       m->err = 0;
-       init_waitqueue_head(&m->equeue);
-       INIT_LIST_HEAD(&m->req_list);
-       INIT_LIST_HEAD(&m->unsent_req_list);
-       m->rcall = NULL;
-       m->rpos = 0;
-       m->rbuf = NULL;
-       m->wpos = m->wsize = 0;
-       m->wbuf = NULL;
-       INIT_WORK(&m->rq, p9_read_work);
-       INIT_WORK(&m->wq, p9_write_work);
-       m->wsched = 0;
-       memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
-       m->poll_task = NULL;
-       n = p9_mux_poll_start(m);
-       if (n) {
-               kfree(m);
-               return ERR_PTR(n);
-       }
-
-       n = trans->poll(trans, &m->pt);
-       if (n & POLLIN) {
-               P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
-               set_bit(Rpending, &m->wsched);
-       }
-
-       if (n & POLLOUT) {
-               P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
-               set_bit(Wpending, &m->wsched);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
-               if (IS_ERR(m->poll_waddr[i])) {
-                       p9_mux_poll_stop(m);
-                       mtmp = (void *)m->poll_waddr;   /* the error code */
-                       kfree(m);
-                       m = mtmp;
-                       break;
-               }
-       }
-
-       return m;
-}
-EXPORT_SYMBOL(p9_conn_create);
-
-/**
- * p9_mux_destroy - cancels all pending requests and frees mux resources
- */
-void p9_conn_destroy(struct p9_conn *m)
-{
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
-               m->mux_list.prev, m->mux_list.next);
-       p9_conn_cancel(m, -ECONNRESET);
-
-       if (!list_empty(&m->req_list)) {
-               /* wait until all processes waiting on this session exit */
-               P9_DPRINTK(P9_DEBUG_MUX,
-                       "mux %p waiting for empty request queue\n", m);
-               wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
-               P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
-                       list_empty(&m->req_list));
-       }
-
-       p9_mux_poll_stop(m);
-       m->trans = NULL;
-       p9_idpool_destroy(m->tagpool);
-       kfree(m);
-}
-EXPORT_SYMBOL(p9_conn_destroy);
-
-/**
- * p9_pollwait - called by files poll operation to add v9fs-poll task
- *     to files wait queue
- */
-static void
-p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
-             poll_table * p)
-{
-       int i;
-       struct p9_conn *m;
-
-       m = container_of(p, struct p9_conn, pt);
-       for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
-               if (m->poll_waddr[i] == NULL)
-                       break;
-
-       if (i >= ARRAY_SIZE(m->poll_waddr)) {
-               P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
-               return;
-       }
-
-       m->poll_waddr[i] = wait_address;
-
-       if (!wait_address) {
-               P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
-               m->poll_waddr[i] = ERR_PTR(-EIO);
-               return;
-       }
-
-       init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task);
-       add_wait_queue(wait_address, &m->poll_wait[i]);
-}
-
-/**
- * p9_poll_mux - polls a mux and schedules read or write works if necessary
- */
-static void p9_poll_mux(struct p9_conn *m)
-{
-       int n;
-
-       if (m->err < 0)
-               return;
-
-       n = m->trans->poll(m->trans, NULL);
-       if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
-               P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n);
-               if (n >= 0)
-                       n = -ECONNRESET;
-               p9_conn_cancel(m, n);
-       }
-
-       if (n & POLLIN) {
-               set_bit(Rpending, &m->wsched);
-               P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
-               if (!test_and_set_bit(Rworksched, &m->wsched)) {
-                       P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
-                       queue_work(p9_mux_wq, &m->rq);
-               }
-       }
-
-       if (n & POLLOUT) {
-               set_bit(Wpending, &m->wsched);
-               P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
-               if ((m->wsize || !list_empty(&m->unsent_req_list))
-                   && !test_and_set_bit(Wworksched, &m->wsched)) {
-                       P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
-                       queue_work(p9_mux_wq, &m->wq);
-               }
-       }
-}
-
-/**
- * p9_poll_proc - polls all v9fs transports for new events and queues
- *     the appropriate work to the work queue
- */
-static int p9_poll_proc(void *a)
-{
-       struct p9_conn *m, *mtmp;
-       struct p9_mux_poll_task *vpt;
-
-       vpt = a;
-       P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt);
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
-                       p9_poll_mux(m);
-               }
-
-               P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
-               schedule_timeout(SCHED_TIMEOUT * HZ);
-       }
-
-       __set_current_state(TASK_RUNNING);
-       P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
-       return 0;
-}
-
-/**
- * p9_write_work - called when a transport can send some data
- */
-static void p9_write_work(struct work_struct *work)
-{
-       int n, err;
-       struct p9_conn *m;
-       struct p9_req *req;
-
-       m = container_of(work, struct p9_conn, wq);
-
-       if (m->err < 0) {
-               clear_bit(Wworksched, &m->wsched);
-               return;
-       }
-
-       if (!m->wsize) {
-               if (list_empty(&m->unsent_req_list)) {
-                       clear_bit(Wworksched, &m->wsched);
-                       return;
-               }
-
-               spin_lock(&m->lock);
-again:
-               req = list_entry(m->unsent_req_list.next, struct p9_req,
-                              req_list);
-               list_move_tail(&req->req_list, &m->req_list);
-               if (req->err == ERREQFLUSH)
-                       goto again;
-
-               m->wbuf = req->tcall->sdata;
-               m->wsize = req->tcall->size;
-               m->wpos = 0;
-               spin_unlock(&m->lock);
-       }
-
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos,
-                                                               m->wsize);
-       clear_bit(Wpending, &m->wsched);
-       err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
-       if (err == -EAGAIN) {
-               clear_bit(Wworksched, &m->wsched);
-               return;
-       }
-
-       if (err < 0)
-               goto error;
-       else if (err == 0) {
-               err = -EREMOTEIO;
-               goto error;
-       }
-
-       m->wpos += err;
-       if (m->wpos == m->wsize)
-               m->wpos = m->wsize = 0;
-
-       if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
-               if (test_and_clear_bit(Wpending, &m->wsched))
-                       n = POLLOUT;
-               else
-                       n = m->trans->poll(m->trans, NULL);
-
-               if (n & POLLOUT) {
-                       P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
-                       queue_work(p9_mux_wq, &m->wq);
-               } else
-                       clear_bit(Wworksched, &m->wsched);
-       } else
-               clear_bit(Wworksched, &m->wsched);
-
-       return;
-
-error:
-       p9_conn_cancel(m, err);
-       clear_bit(Wworksched, &m->wsched);
-}
-
-static void process_request(struct p9_conn *m, struct p9_req *req)
-{
-       int ecode;
-       struct p9_str *ename;
-
-       if (!req->err && req->rcall->id == P9_RERROR) {
-               ecode = req->rcall->params.rerror.errno;
-               ename = &req->rcall->params.rerror.error;
-
-               P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
-                                                               ename->str);
-
-               if (*m->extended)
-                       req->err = -ecode;
-
-               if (!req->err) {
-                       req->err = p9_errstr2errno(ename->str, ename->len);
-
-                       if (!req->err) {        /* string match failed */
-                               PRINT_FCALL_ERROR("unknown error", req->rcall);
-                       }
-
-                       if (!req->err)
-                               req->err = -ESERVERFAULT;
-               }
-       } else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
-               P9_DPRINTK(P9_DEBUG_ERROR,
-                               "fcall mismatch: expected %d, got %d\n",
-                               req->tcall->id + 1, req->rcall->id);
-               if (!req->err)
-                       req->err = -EIO;
-       }
-}
-
-/**
- * p9_read_work - called when there is some data to be read from a transport
- */
-static void p9_read_work(struct work_struct *work)
-{
-       int n, err;
-       struct p9_conn *m;
-       struct p9_req *req, *rptr, *rreq;
-       struct p9_fcall *rcall;
-       char *rbuf;
-
-       m = container_of(work, struct p9_conn, rq);
-
-       if (m->err < 0)
-               return;
-
-       rcall = NULL;
-       P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
-
-       if (!m->rcall) {
-               m->rcall =
-                   kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL);
-               if (!m->rcall) {
-                       err = -ENOMEM;
-                       goto error;
-               }
-
-               m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
-               m->rpos = 0;
-       }
-
-       clear_bit(Rpending, &m->wsched);
-       err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
-       if (err == -EAGAIN) {
-               clear_bit(Rworksched, &m->wsched);
-               return;
-       }
-
-       if (err <= 0)
-               goto error;
-
-       m->rpos += err;
-       while (m->rpos > 4) {
-               n = le32_to_cpu(*(__le32 *) m->rbuf);
-               if (n >= m->msize) {
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                               "requested packet size too big: %d\n", n);
-                       err = -EIO;
-                       goto error;
-               }
-
-               if (m->rpos < n)
-                       break;
-
-               err =
-                   p9_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
-               if (err < 0) {
-                       goto error;
-               }
-
-#ifdef CONFIG_NET_9P_DEBUG
-               if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
-                       char buf[150];
-
-                       p9_printfcall(buf, sizeof(buf), m->rcall,
-                               *m->extended);
-                       printk(KERN_NOTICE ">>> %p %s\n", m, buf);
-               }
-#endif
-
-               rcall = m->rcall;
-               rbuf = m->rbuf;
-               if (m->rpos > n) {
-                       m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,
-                                          GFP_KERNEL);
-                       if (!m->rcall) {
-                               err = -ENOMEM;
-                               goto error;
-                       }
-
-                       m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
-                       memmove(m->rbuf, rbuf + n, m->rpos - n);
-                       m->rpos -= n;
-               } else {
-                       m->rcall = NULL;
-                       m->rbuf = NULL;
-                       m->rpos = 0;
-               }
-
-               P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
-                                                       rcall->id, rcall->tag);
-
-               req = NULL;
-               spin_lock(&m->lock);
-               list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
-                       if (rreq->tag == rcall->tag) {
-                               req = rreq;
-                               if (req->flush != Flushing)
-                                       list_del(&req->req_list);
-                               break;
-                       }
-               }
-               spin_unlock(&m->lock);
-
-               if (req) {
-                       req->rcall = rcall;
-                       process_request(m, req);
-
-                       if (req->flush != Flushing) {
-                               if (req->cb)
-                                       (*req->cb) (req, req->cba);
-                               else
-                                       kfree(req->rcall);
-
-                               wake_up(&m->equeue);
-                       }
-               } else {
-                       if (err >= 0 && rcall->id != P9_RFLUSH)
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                 "unexpected response mux %p id %d tag %d\n",
-                                 m, rcall->id, rcall->tag);
-                       kfree(rcall);
-               }
-       }
-
-       if (!list_empty(&m->req_list)) {
-               if (test_and_clear_bit(Rpending, &m->wsched))
-                       n = POLLIN;
-               else
-                       n = m->trans->poll(m->trans, NULL);
-
-               if (n & POLLIN) {
-                       P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
-                       queue_work(p9_mux_wq, &m->rq);
-               } else
-                       clear_bit(Rworksched, &m->wsched);
-       } else
-               clear_bit(Rworksched, &m->wsched);
-
-       return;
-
-error:
-       p9_conn_cancel(m, err);
-       clear_bit(Rworksched, &m->wsched);
-}
-
-/**
- * p9_send_request - send 9P request
- * The function can sleep until the request is scheduled for sending.
- * The function can be interrupted. Return from the function is not
- * a guarantee that the request is sent successfully. Can return errors
- * that can be retrieved by PTR_ERR macros.
- *
- * @m: mux data
- * @tc: request to be sent
- * @cb: callback function to call when response is received
- * @cba: parameter to pass to the callback function
- */
-static struct p9_req *p9_send_request(struct p9_conn *m,
-                                         struct p9_fcall *tc,
-                                         p9_conn_req_callback cb, void *cba)
-{
-       int n;
-       struct p9_req *req;
-
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
-               tc, tc->id);
-       if (m->err < 0)
-               return ERR_PTR(m->err);
-
-       req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);
-       if (!req)
-               return ERR_PTR(-ENOMEM);
-
-       if (tc->id == P9_TVERSION)
-               n = P9_NOTAG;
-       else
-               n = p9_mux_get_tag(m);
-
-       if (n < 0)
-               return ERR_PTR(-ENOMEM);
-
-       p9_set_tag(tc, n);
-
-#ifdef CONFIG_NET_9P_DEBUG
-       if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
-               char buf[150];
-
-               p9_printfcall(buf, sizeof(buf), tc, *m->extended);
-               printk(KERN_NOTICE "<<< %p %s\n", m, buf);
-       }
-#endif
-
-       spin_lock_init(&req->lock);
-       req->tag = n;
-       req->tcall = tc;
-       req->rcall = NULL;
-       req->err = 0;
-       req->cb = cb;
-       req->cba = cba;
-       req->flush = None;
-
-       spin_lock(&m->lock);
-       list_add_tail(&req->req_list, &m->unsent_req_list);
-       spin_unlock(&m->lock);
-
-       if (test_and_clear_bit(Wpending, &m->wsched))
-               n = POLLOUT;
-       else
-               n = m->trans->poll(m->trans, NULL);
-
-       if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
-               queue_work(p9_mux_wq, &m->wq);
-
-       return req;
-}
-
-static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req)
-{
-       p9_mux_put_tag(m, req->tag);
-       kfree(req);
-}
-
-static void p9_mux_flush_cb(struct p9_req *freq, void *a)
-{
-       p9_conn_req_callback cb;
-       int tag;
-       struct p9_conn *m;
-       struct p9_req *req, *rreq, *rptr;
-
-       m = a;
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
-               freq->tcall, freq->rcall, freq->err,
-               freq->tcall->params.tflush.oldtag);
-
-       spin_lock(&m->lock);
-       cb = NULL;
-       tag = freq->tcall->params.tflush.oldtag;
-       req = NULL;
-       list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
-               if (rreq->tag == tag) {
-                       req = rreq;
-                       list_del(&req->req_list);
-                       break;
-               }
-       }
-       spin_unlock(&m->lock);
-
-       if (req) {
-               spin_lock(&req->lock);
-               req->flush = Flushed;
-               spin_unlock(&req->lock);
-
-               if (req->cb)
-                       (*req->cb) (req, req->cba);
-               else
-                       kfree(req->rcall);
-
-               wake_up(&m->equeue);
-       }
-
-       kfree(freq->tcall);
-       kfree(freq->rcall);
-       p9_mux_free_request(m, freq);
-}
-
-static int
-p9_mux_flush_request(struct p9_conn *m, struct p9_req *req)
-{
-       struct p9_fcall *fc;
-       struct p9_req *rreq, *rptr;
-
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
-
-       /* if a response was received for a request, do nothing */
-       spin_lock(&req->lock);
-       if (req->rcall || req->err) {
-               spin_unlock(&req->lock);
-               P9_DPRINTK(P9_DEBUG_MUX,
-                       "mux %p req %p response already received\n", m, req);
-               return 0;
-       }
-
-       req->flush = Flushing;
-       spin_unlock(&req->lock);
-
-       spin_lock(&m->lock);
-       /* if the request is not sent yet, just remove it from the list */
-       list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
-               if (rreq->tag == req->tag) {
-                       P9_DPRINTK(P9_DEBUG_MUX,
-                          "mux %p req %p request is not sent yet\n", m, req);
-                       list_del(&rreq->req_list);
-                       req->flush = Flushed;
-                       spin_unlock(&m->lock);
-                       if (req->cb)
-                               (*req->cb) (req, req->cba);
-                       return 0;
-               }
-       }
-       spin_unlock(&m->lock);
-
-       clear_thread_flag(TIF_SIGPENDING);
-       fc = p9_create_tflush(req->tag);
-       p9_send_request(m, fc, p9_mux_flush_cb, m);
-       return 1;
-}
-
-static void
-p9_conn_rpc_cb(struct p9_req *req, void *a)
-{
-       struct p9_mux_rpc *r;
-
-       P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);
-       r = a;
-       r->rcall = req->rcall;
-       r->err = req->err;
-
-       if (req->flush != None && !req->err)
-               r->err = -ERESTARTSYS;
-
-       wake_up(&r->wqueue);
-}
-
-/**
- * p9_mux_rpc - sends 9P request and waits until a response is available.
- *     The function can be interrupted.
- * @m: mux data
- * @tc: request to be sent
- * @rc: pointer where a pointer to the response is stored
- */
-int
-p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc,
-            struct p9_fcall **rc)
-{
-       int err, sigpending;
-       unsigned long flags;
-       struct p9_req *req;
-       struct p9_mux_rpc r;
-
-       r.err = 0;
-       r.tcall = tc;
-       r.rcall = NULL;
-       r.m = m;
-       init_waitqueue_head(&r.wqueue);
-
-       if (rc)
-               *rc = NULL;
-
-       sigpending = 0;
-       if (signal_pending(current)) {
-               sigpending = 1;
-               clear_thread_flag(TIF_SIGPENDING);
-       }
-
-       req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);
-       if (IS_ERR(req)) {
-               err = PTR_ERR(req);
-               P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
-               return err;
-       }
-
-       err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);
-       if (r.err < 0)
-               err = r.err;
-
-       if (err == -ERESTARTSYS && m->trans->status == Connected
-                                                       && m->err == 0) {
-               if (p9_mux_flush_request(m, req)) {
-                       /* wait until we get response of the flush message */
-                       do {
-                               clear_thread_flag(TIF_SIGPENDING);
-                               err = wait_event_interruptible(r.wqueue,
-                                       r.rcall || r.err);
-                       } while (!r.rcall && !r.err && err == -ERESTARTSYS &&
-                               m->trans->status == Connected && !m->err);
-
-                       err = -ERESTARTSYS;
-               }
-               sigpending = 1;
-       }
-
-       if (sigpending) {
-               spin_lock_irqsave(&current->sighand->siglock, flags);
-               recalc_sigpending();
-               spin_unlock_irqrestore(&current->sighand->siglock, flags);
-       }
-
-       if (rc)
-               *rc = r.rcall;
-       else
-               kfree(r.rcall);
-
-       p9_mux_free_request(m, req);
-       if (err > 0)
-               err = -EIO;
-
-       return err;
-}
-EXPORT_SYMBOL(p9_conn_rpc);
-
-#ifdef P9_NONBLOCK
-/**
- * p9_conn_rpcnb - sends 9P request without waiting for response.
- * @m: mux data
- * @tc: request to be sent
- * @cb: callback function to be called when response arrives
- * @cba: value to pass to the callback function
- */
-int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
-                  p9_conn_req_callback cb, void *a)
-{
-       int err;
-       struct p9_req *req;
-
-       req = p9_send_request(m, tc, cb, a);
-       if (IS_ERR(req)) {
-               err = PTR_ERR(req);
-               P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
-               return PTR_ERR(req);
-       }
-
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
-       return 0;
-}
-EXPORT_SYMBOL(p9_conn_rpcnb);
-#endif /* P9_NONBLOCK */
-
-/**
- * p9_conn_cancel - cancel all pending requests with error
- * @m: mux data
- * @err: error code
- */
-void p9_conn_cancel(struct p9_conn *m, int err)
-{
-       struct p9_req *req, *rtmp;
-       LIST_HEAD(cancel_list);
-
-       P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
-       m->err = err;
-       spin_lock(&m->lock);
-       list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
-               list_move(&req->req_list, &cancel_list);
-       }
-       list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
-               list_move(&req->req_list, &cancel_list);
-       }
-       spin_unlock(&m->lock);
-
-       list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
-               list_del(&req->req_list);
-               if (!req->err)
-                       req->err = err;
-
-               if (req->cb)
-                       (*req->cb) (req, req->cba);
-               else
-                       kfree(req->rcall);
-       }
-
-       wake_up(&m->equeue);
-}
-EXPORT_SYMBOL(p9_conn_cancel);
-
-static u16 p9_mux_get_tag(struct p9_conn *m)
-{
-       int tag;
-
-       tag = p9_idpool_get(m->tagpool);
-       if (tag < 0)
-               return P9_NOTAG;
-       else
-               return (u16) tag;
-}
-
-static void p9_mux_put_tag(struct p9_conn *m, u16 tag)
-{
-       if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool))
-               p9_idpool_put(tag, m->tagpool);
-}
index 62332ed9da4afcd7e8b06577f0e4ec47d07ed171..1aa9d51753981c483b7778e28c0f9a026714c7c2 100644 (file)
@@ -5,7 +5,7 @@
  *
  *  Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
  *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
- *  Copyright (C) 2004-2007 by Eric Van Hensbergen <ericvh@gmail.com>
+ *  Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
  *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/ipv6.h>
+#include <linux/kthread.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/un.h>
@@ -42,7 +43,9 @@
 
 #define P9_PORT 564
 #define MAX_SOCK_BUF (64*1024)
-
+#define ERREQFLUSH     1
+#define SCHED_TIMEOUT  10
+#define MAXPOLLWADDR   2
 
 struct p9_fd_opts {
        int rfd;
@@ -53,6 +56,7 @@ struct p9_fd_opts {
 struct p9_trans_fd {
        struct file *rd;
        struct file *wr;
+       struct p9_conn *conn;
 };
 
 /*
@@ -72,6 +76,1028 @@ static match_table_t tokens = {
        {Opt_err, NULL},
 };
 
+enum {
+       Rworksched = 1,         /* read work scheduled or running */
+       Rpending = 2,           /* can read */
+       Wworksched = 4,         /* write work scheduled or running */
+       Wpending = 8,           /* can write */
+};
+
+enum {
+       None,
+       Flushing,
+       Flushed,
+};
+
+struct p9_req;
+
+typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
+struct p9_req {
+       spinlock_t lock; /* protect request structure */
+       int tag;
+       struct p9_fcall *tcall;
+       struct p9_fcall *rcall;
+       int err;
+       p9_conn_req_callback cb;
+       void *cba;
+       int flush;
+       struct list_head req_list;
+};
+
+struct p9_mux_poll_task;
+
+struct p9_conn {
+       spinlock_t lock; /* protect lock structure */
+       struct list_head mux_list;
+       struct p9_mux_poll_task *poll_task;
+       int msize;
+       unsigned char extended;
+       struct p9_trans *trans;
+       struct p9_idpool *tagpool;
+       int err;
+       wait_queue_head_t equeue;
+       struct list_head req_list;
+       struct list_head unsent_req_list;
+       struct p9_fcall *rcall;
+       int rpos;
+       char *rbuf;
+       int wpos;
+       int wsize;
+       char *wbuf;
+       wait_queue_t poll_wait[MAXPOLLWADDR];
+       wait_queue_head_t *poll_waddr[MAXPOLLWADDR];
+       poll_table pt;
+       struct work_struct rq;
+       struct work_struct wq;
+       unsigned long wsched;
+};
+
+struct p9_mux_poll_task {
+       struct task_struct *task;
+       struct list_head mux_list;
+       int muxnum;
+};
+
+struct p9_mux_rpc {
+       struct p9_conn *m;
+       int err;
+       struct p9_fcall *tcall;
+       struct p9_fcall *rcall;
+       wait_queue_head_t wqueue;
+};
+
+static int p9_poll_proc(void *);
+static void p9_read_work(struct work_struct *work);
+static void p9_write_work(struct work_struct *work);
+static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
+                                                               poll_table *p);
+static int p9_fd_write(struct p9_trans *trans, void *v, int len);
+static int p9_fd_read(struct p9_trans *trans, void *v, int len);
+
+static DEFINE_MUTEX(p9_mux_task_lock);
+static struct workqueue_struct *p9_mux_wq;
+
+static int p9_mux_num;
+static int p9_mux_poll_task_num;
+static struct p9_mux_poll_task p9_mux_poll_tasks[100];
+
+static void p9_conn_destroy(struct p9_conn *);
+static unsigned int p9_fd_poll(struct p9_trans *trans,
+                                               struct poll_table_struct *pt);
+
+#ifdef P9_NONBLOCK
+static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
+       p9_conn_req_callback cb, void *a);
+#endif /* P9_NONBLOCK */
+
+static void p9_conn_cancel(struct p9_conn *m, int err);
+
+static int p9_mux_global_init(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
+               p9_mux_poll_tasks[i].task = NULL;
+
+       p9_mux_wq = create_workqueue("v9fs");
+       if (!p9_mux_wq) {
+               printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static u16 p9_mux_get_tag(struct p9_conn *m)
+{
+       int tag;
+
+       tag = p9_idpool_get(m->tagpool);
+       if (tag < 0)
+               return P9_NOTAG;
+       else
+               return (u16) tag;
+}
+
+static void p9_mux_put_tag(struct p9_conn *m, u16 tag)
+{
+       if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool))
+               p9_idpool_put(tag, m->tagpool);
+}
+
+/**
+ * p9_mux_calc_poll_procs - calculates the number of polling procs
+ * based on the number of mounted v9fs filesystems.
+ *
+ * The current implementation returns sqrt of the number of mounts.
+ */
+static int p9_mux_calc_poll_procs(int muxnum)
+{
+       int n;
+
+       if (p9_mux_poll_task_num)
+               n = muxnum / p9_mux_poll_task_num +
+                   (muxnum % p9_mux_poll_task_num ? 1 : 0);
+       else
+               n = 1;
+
+       if (n > ARRAY_SIZE(p9_mux_poll_tasks))
+               n = ARRAY_SIZE(p9_mux_poll_tasks);
+
+       return n;
+}
+
+static int p9_mux_poll_start(struct p9_conn *m)
+{
+       int i, n;
+       struct p9_mux_poll_task *vpt, *vptlast;
+       struct task_struct *pproc;
+
+       P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num,
+               p9_mux_poll_task_num);
+       mutex_lock(&p9_mux_task_lock);
+
+       n = p9_mux_calc_poll_procs(p9_mux_num + 1);
+       if (n > p9_mux_poll_task_num) {
+               for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
+                       if (p9_mux_poll_tasks[i].task == NULL) {
+                               vpt = &p9_mux_poll_tasks[i];
+                               P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n",
+                                                                       vpt);
+                               pproc = kthread_create(p9_poll_proc, vpt,
+                                                               "v9fs-poll");
+
+                               if (!IS_ERR(pproc)) {
+                                       vpt->task = pproc;
+                                       INIT_LIST_HEAD(&vpt->mux_list);
+                                       vpt->muxnum = 0;
+                                       p9_mux_poll_task_num++;
+                                       wake_up_process(vpt->task);
+                               }
+                               break;
+                       }
+               }
+
+               if (i >= ARRAY_SIZE(p9_mux_poll_tasks))
+                       P9_DPRINTK(P9_DEBUG_ERROR,
+                                       "warning: no free poll slots\n");
+       }
+
+       n = (p9_mux_num + 1) / p9_mux_poll_task_num +
+           ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0);
+
+       vptlast = NULL;
+       for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
+               vpt = &p9_mux_poll_tasks[i];
+               if (vpt->task != NULL) {
+                       vptlast = vpt;
+                       if (vpt->muxnum < n) {
+                               P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
+                               list_add(&m->mux_list, &vpt->mux_list);
+                               vpt->muxnum++;
+                               m->poll_task = vpt;
+                               memset(&m->poll_waddr, 0,
+                                                       sizeof(m->poll_waddr));
+                               init_poll_funcptr(&m->pt, p9_pollwait);
+                               break;
+                       }
+               }
+       }
+
+       if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) {
+               if (vptlast == NULL) {
+                       mutex_unlock(&p9_mux_task_lock);
+                       return -ENOMEM;
+               }
+
+               P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
+               list_add(&m->mux_list, &vptlast->mux_list);
+               vptlast->muxnum++;
+               m->poll_task = vptlast;
+               memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
+               init_poll_funcptr(&m->pt, p9_pollwait);
+       }
+
+       p9_mux_num++;
+       mutex_unlock(&p9_mux_task_lock);
+
+       return 0;
+}
+
+static void p9_mux_poll_stop(struct p9_conn *m)
+{
+       int i;
+       struct p9_mux_poll_task *vpt;
+
+       mutex_lock(&p9_mux_task_lock);
+       vpt = m->poll_task;
+       list_del(&m->mux_list);
+       for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+               if (m->poll_waddr[i] != NULL) {
+                       remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
+                       m->poll_waddr[i] = NULL;
+               }
+       }
+       vpt->muxnum--;
+       if (!vpt->muxnum) {
+               P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt);
+               kthread_stop(vpt->task);
+               vpt->task = NULL;
+               p9_mux_poll_task_num--;
+       }
+       p9_mux_num--;
+       mutex_unlock(&p9_mux_task_lock);
+}
+
+/**
+ * p9_conn_create - allocate and initialize the per-session mux data
+ * Creates the polling task if this is the first session.
+ *
+ * @trans - transport structure
+ * @msize - maximum message size
+ * @extended - extended flag
+ */
+static struct p9_conn *p9_conn_create(struct p9_trans *trans)
+{
+       int i, n;
+       struct p9_conn *m, *mtmp;
+
+       P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans,
+                                                               trans->msize);
+       m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL);
+       if (!m)
+               return ERR_PTR(-ENOMEM);
+
+       spin_lock_init(&m->lock);
+       INIT_LIST_HEAD(&m->mux_list);
+       m->msize = trans->msize;
+       m->extended = trans->extended;
+       m->trans = trans;
+       m->tagpool = p9_idpool_create();
+       if (IS_ERR(m->tagpool)) {
+               mtmp = ERR_PTR(-ENOMEM);
+               kfree(m);
+               return mtmp;
+       }
+
+       m->err = 0;
+       init_waitqueue_head(&m->equeue);
+       INIT_LIST_HEAD(&m->req_list);
+       INIT_LIST_HEAD(&m->unsent_req_list);
+       m->rcall = NULL;
+       m->rpos = 0;
+       m->rbuf = NULL;
+       m->wpos = m->wsize = 0;
+       m->wbuf = NULL;
+       INIT_WORK(&m->rq, p9_read_work);
+       INIT_WORK(&m->wq, p9_write_work);
+       m->wsched = 0;
+       memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
+       m->poll_task = NULL;
+       n = p9_mux_poll_start(m);
+       if (n) {
+               kfree(m);
+               return ERR_PTR(n);
+       }
+
+       n = p9_fd_poll(trans, &m->pt);
+       if (n & POLLIN) {
+               P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
+               set_bit(Rpending, &m->wsched);
+       }
+
+       if (n & POLLOUT) {
+               P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
+               set_bit(Wpending, &m->wsched);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+               if (IS_ERR(m->poll_waddr[i])) {
+                       p9_mux_poll_stop(m);
+                       mtmp = (void *)m->poll_waddr;   /* the error code */
+                       kfree(m);
+                       m = mtmp;
+                       break;
+               }
+       }
+
+       return m;
+}
+
+/**
+ * p9_mux_destroy - cancels all pending requests and frees mux resources
+ */
+static void p9_conn_destroy(struct p9_conn *m)
+{
+       P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
+               m->mux_list.prev, m->mux_list.next);
+       p9_conn_cancel(m, -ECONNRESET);
+
+       if (!list_empty(&m->req_list)) {
+               /* wait until all processes waiting on this session exit */
+               P9_DPRINTK(P9_DEBUG_MUX,
+                       "mux %p waiting for empty request queue\n", m);
+               wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
+               P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
+                       list_empty(&m->req_list));
+       }
+
+       p9_mux_poll_stop(m);
+       m->trans = NULL;
+       p9_idpool_destroy(m->tagpool);
+       kfree(m);
+}
+
+/**
+ * p9_pollwait - called by files poll operation to add v9fs-poll task
+ *     to files wait queue
+ */
+static void
+p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
+{
+       int i;
+       struct p9_conn *m;
+
+       m = container_of(p, struct p9_conn, pt);
+       for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
+               if (m->poll_waddr[i] == NULL)
+                       break;
+
+       if (i >= ARRAY_SIZE(m->poll_waddr)) {
+               P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
+               return;
+       }
+
+       m->poll_waddr[i] = wait_address;
+
+       if (!wait_address) {
+               P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
+               m->poll_waddr[i] = ERR_PTR(-EIO);
+               return;
+       }
+
+       init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task);
+       add_wait_queue(wait_address, &m->poll_wait[i]);
+}
+
+/**
+ * p9_poll_mux - polls a mux and schedules read or write works if necessary
+ */
+static void p9_poll_mux(struct p9_conn *m)
+{
+       int n;
+
+       if (m->err < 0)
+               return;
+
+       n = p9_fd_poll(m->trans, NULL);
+       if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
+               P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n);
+               if (n >= 0)
+                       n = -ECONNRESET;
+               p9_conn_cancel(m, n);
+       }
+
+       if (n & POLLIN) {
+               set_bit(Rpending, &m->wsched);
+               P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
+               if (!test_and_set_bit(Rworksched, &m->wsched)) {
+                       P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
+                       queue_work(p9_mux_wq, &m->rq);
+               }
+       }
+
+       if (n & POLLOUT) {
+               set_bit(Wpending, &m->wsched);
+               P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
+               if ((m->wsize || !list_empty(&m->unsent_req_list))
+                   && !test_and_set_bit(Wworksched, &m->wsched)) {
+                       P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
+                       queue_work(p9_mux_wq, &m->wq);
+               }
+       }
+}
+
+/**
+ * p9_poll_proc - polls all v9fs transports for new events and queues
+ *     the appropriate work to the work queue
+ */
+static int p9_poll_proc(void *a)
+{
+       struct p9_conn *m, *mtmp;
+       struct p9_mux_poll_task *vpt;
+
+       vpt = a;
+       P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt);
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
+                       p9_poll_mux(m);
+               }
+
+               P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
+               schedule_timeout(SCHED_TIMEOUT * HZ);
+       }
+
+       __set_current_state(TASK_RUNNING);
+       P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
+       return 0;
+}
+
+/**
+ * p9_write_work - called when a transport can send some data
+ */
+static void p9_write_work(struct work_struct *work)
+{
+       int n, err;
+       struct p9_conn *m;
+       struct p9_req *req;
+
+       m = container_of(work, struct p9_conn, wq);
+
+       if (m->err < 0) {
+               clear_bit(Wworksched, &m->wsched);
+               return;
+       }
+
+       if (!m->wsize) {
+               if (list_empty(&m->unsent_req_list)) {
+                       clear_bit(Wworksched, &m->wsched);
+                       return;
+               }
+
+               spin_lock(&m->lock);
+again:
+               req = list_entry(m->unsent_req_list.next, struct p9_req,
+                              req_list);
+               list_move_tail(&req->req_list, &m->req_list);
+               if (req->err == ERREQFLUSH)
+                       goto again;
+
+               m->wbuf = req->tcall->sdata;
+               m->wsize = req->tcall->size;
+               m->wpos = 0;
+               spin_unlock(&m->lock);
+       }
+
+       P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos,
+                                                               m->wsize);
+       clear_bit(Wpending, &m->wsched);
+       err = p9_fd_write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
+       P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
+       if (err == -EAGAIN) {
+               clear_bit(Wworksched, &m->wsched);
+               return;
+       }
+
+       if (err < 0)
+               goto error;
+       else if (err == 0) {
+               err = -EREMOTEIO;
+               goto error;
+       }
+
+       m->wpos += err;
+       if (m->wpos == m->wsize)
+               m->wpos = m->wsize = 0;
+
+       if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
+               if (test_and_clear_bit(Wpending, &m->wsched))
+                       n = POLLOUT;
+               else
+                       n = p9_fd_poll(m->trans, NULL);
+
+               if (n & POLLOUT) {
+                       P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
+                       queue_work(p9_mux_wq, &m->wq);
+               } else
+                       clear_bit(Wworksched, &m->wsched);
+       } else
+               clear_bit(Wworksched, &m->wsched);
+
+       return;
+
+error:
+       p9_conn_cancel(m, err);
+       clear_bit(Wworksched, &m->wsched);
+}
+
+static void process_request(struct p9_conn *m, struct p9_req *req)
+{
+       int ecode;
+       struct p9_str *ename;
+
+       if (!req->err && req->rcall->id == P9_RERROR) {
+               ecode = req->rcall->params.rerror.errno;
+               ename = &req->rcall->params.rerror.error;
+
+               P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
+                                                               ename->str);
+
+               if (m->extended)
+                       req->err = -ecode;
+
+               if (!req->err) {
+                       req->err = p9_errstr2errno(ename->str, ename->len);
+
+                       /* string match failed */
+                       if (!req->err) {
+                               PRINT_FCALL_ERROR("unknown error", req->rcall);
+                               req->err = -ESERVERFAULT;
+                       }
+               }
+       } else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
+               P9_DPRINTK(P9_DEBUG_ERROR,
+                               "fcall mismatch: expected %d, got %d\n",
+                               req->tcall->id + 1, req->rcall->id);
+               if (!req->err)
+                       req->err = -EIO;
+       }
+}
+
+/**
+ * p9_read_work - called when there is some data to be read from a transport
+ */
+static void p9_read_work(struct work_struct *work)
+{
+       int n, err;
+       struct p9_conn *m;
+       struct p9_req *req, *rptr, *rreq;
+       struct p9_fcall *rcall;
+       char *rbuf;
+
+       m = container_of(work, struct p9_conn, rq);
+
+       if (m->err < 0)
+               return;
+
+       rcall = NULL;
+       P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
+
+       if (!m->rcall) {
+               m->rcall =
+                   kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL);
+               if (!m->rcall) {
+                       err = -ENOMEM;
+                       goto error;
+               }
+
+               m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
+               m->rpos = 0;
+       }
+
+       clear_bit(Rpending, &m->wsched);
+       err = p9_fd_read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
+       P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
+       if (err == -EAGAIN) {
+               clear_bit(Rworksched, &m->wsched);
+               return;
+       }
+
+       if (err <= 0)
+               goto error;
+
+       m->rpos += err;
+       while (m->rpos > 4) {
+               n = le32_to_cpu(*(__le32 *) m->rbuf);
+               if (n >= m->msize) {
+                       P9_DPRINTK(P9_DEBUG_ERROR,
+                               "requested packet size too big: %d\n", n);
+                       err = -EIO;
+                       goto error;
+               }
+
+               if (m->rpos < n)
+                       break;
+
+               err =
+                   p9_deserialize_fcall(m->rbuf, n, m->rcall, m->extended);
+               if (err < 0)
+                       goto error;
+
+#ifdef CONFIG_NET_9P_DEBUG
+               if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
+                       char buf[150];
+
+                       p9_printfcall(buf, sizeof(buf), m->rcall,
+                               m->extended);
+                       printk(KERN_NOTICE ">>> %p %s\n", m, buf);
+               }
+#endif
+
+               rcall = m->rcall;
+               rbuf = m->rbuf;
+               if (m->rpos > n) {
+                       m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,
+                                          GFP_KERNEL);
+                       if (!m->rcall) {
+                               err = -ENOMEM;
+                               goto error;
+                       }
+
+                       m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
+                       memmove(m->rbuf, rbuf + n, m->rpos - n);
+                       m->rpos -= n;
+               } else {
+                       m->rcall = NULL;
+                       m->rbuf = NULL;
+                       m->rpos = 0;
+               }
+
+               P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
+                                                       rcall->id, rcall->tag);
+
+               req = NULL;
+               spin_lock(&m->lock);
+               list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
+                       if (rreq->tag == rcall->tag) {
+                               req = rreq;
+                               if (req->flush != Flushing)
+                                       list_del(&req->req_list);
+                               break;
+                       }
+               }
+               spin_unlock(&m->lock);
+
+               if (req) {
+                       req->rcall = rcall;
+                       process_request(m, req);
+
+                       if (req->flush != Flushing) {
+                               if (req->cb)
+                                       (*req->cb) (req, req->cba);
+                               else
+                                       kfree(req->rcall);
+
+                               wake_up(&m->equeue);
+                       }
+               } else {
+                       if (err >= 0 && rcall->id != P9_RFLUSH)
+                               P9_DPRINTK(P9_DEBUG_ERROR,
+                                 "unexpected response mux %p id %d tag %d\n",
+                                 m, rcall->id, rcall->tag);
+                       kfree(rcall);
+               }
+       }
+
+       if (!list_empty(&m->req_list)) {
+               if (test_and_clear_bit(Rpending, &m->wsched))
+                       n = POLLIN;
+               else
+                       n = p9_fd_poll(m->trans, NULL);
+
+               if (n & POLLIN) {
+                       P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
+                       queue_work(p9_mux_wq, &m->rq);
+               } else
+                       clear_bit(Rworksched, &m->wsched);
+       } else
+               clear_bit(Rworksched, &m->wsched);
+
+       return;
+
+error:
+       p9_conn_cancel(m, err);
+       clear_bit(Rworksched, &m->wsched);
+}
+
+/**
+ * p9_send_request - send 9P request
+ * The function can sleep until the request is scheduled for sending.
+ * The function can be interrupted. Return from the function is not
+ * a guarantee that the request is sent successfully. Can return errors
+ * that can be retrieved by PTR_ERR macros.
+ *
+ * @m: mux data
+ * @tc: request to be sent
+ * @cb: callback function to call when response is received
+ * @cba: parameter to pass to the callback function
+ */
+static struct p9_req *p9_send_request(struct p9_conn *m,
+                                         struct p9_fcall *tc,
+                                         p9_conn_req_callback cb, void *cba)
+{
+       int n;
+       struct p9_req *req;
+
+       P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
+               tc, tc->id);
+       if (m->err < 0)
+               return ERR_PTR(m->err);
+
+       req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       if (tc->id == P9_TVERSION)
+               n = P9_NOTAG;
+       else
+               n = p9_mux_get_tag(m);
+
+       if (n < 0)
+               return ERR_PTR(-ENOMEM);
+
+       p9_set_tag(tc, n);
+
+#ifdef CONFIG_NET_9P_DEBUG
+       if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
+               char buf[150];
+
+               p9_printfcall(buf, sizeof(buf), tc, m->extended);
+               printk(KERN_NOTICE "<<< %p %s\n", m, buf);
+       }
+#endif
+
+       spin_lock_init(&req->lock);
+       req->tag = n;
+       req->tcall = tc;
+       req->rcall = NULL;
+       req->err = 0;
+       req->cb = cb;
+       req->cba = cba;
+       req->flush = None;
+
+       spin_lock(&m->lock);
+       list_add_tail(&req->req_list, &m->unsent_req_list);
+       spin_unlock(&m->lock);
+
+       if (test_and_clear_bit(Wpending, &m->wsched))
+               n = POLLOUT;
+       else
+               n = p9_fd_poll(m->trans, NULL);
+
+       if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
+               queue_work(p9_mux_wq, &m->wq);
+
+       return req;
+}
+
+static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req)
+{
+       p9_mux_put_tag(m, req->tag);
+       kfree(req);
+}
+
+static void p9_mux_flush_cb(struct p9_req *freq, void *a)
+{
+       p9_conn_req_callback cb;
+       int tag;
+       struct p9_conn *m;
+       struct p9_req *req, *rreq, *rptr;
+
+       m = a;
+       P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
+               freq->tcall, freq->rcall, freq->err,
+               freq->tcall->params.tflush.oldtag);
+
+       spin_lock(&m->lock);
+       cb = NULL;
+       tag = freq->tcall->params.tflush.oldtag;
+       req = NULL;
+       list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
+               if (rreq->tag == tag) {
+                       req = rreq;
+                       list_del(&req->req_list);
+                       break;
+               }
+       }
+       spin_unlock(&m->lock);
+
+       if (req) {
+               spin_lock(&req->lock);
+               req->flush = Flushed;
+               spin_unlock(&req->lock);
+
+               if (req->cb)
+                       (*req->cb) (req, req->cba);
+               else
+                       kfree(req->rcall);
+
+               wake_up(&m->equeue);
+       }
+
+       kfree(freq->tcall);
+       kfree(freq->rcall);
+       p9_mux_free_request(m, freq);
+}
+
+static int
+p9_mux_flush_request(struct p9_conn *m, struct p9_req *req)
+{
+       struct p9_fcall *fc;
+       struct p9_req *rreq, *rptr;
+
+       P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
+
+       /* if a response was received for a request, do nothing */
+       spin_lock(&req->lock);
+       if (req->rcall || req->err) {
+               spin_unlock(&req->lock);
+               P9_DPRINTK(P9_DEBUG_MUX,
+                       "mux %p req %p response already received\n", m, req);
+               return 0;
+       }
+
+       req->flush = Flushing;
+       spin_unlock(&req->lock);
+
+       spin_lock(&m->lock);
+       /* if the request is not sent yet, just remove it from the list */
+       list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
+               if (rreq->tag == req->tag) {
+                       P9_DPRINTK(P9_DEBUG_MUX,
+                          "mux %p req %p request is not sent yet\n", m, req);
+                       list_del(&rreq->req_list);
+                       req->flush = Flushed;
+                       spin_unlock(&m->lock);
+                       if (req->cb)
+                               (*req->cb) (req, req->cba);
+                       return 0;
+               }
+       }
+       spin_unlock(&m->lock);
+
+       clear_thread_flag(TIF_SIGPENDING);
+       fc = p9_create_tflush(req->tag);
+       p9_send_request(m, fc, p9_mux_flush_cb, m);
+       return 1;
+}
+
+static void
+p9_conn_rpc_cb(struct p9_req *req, void *a)
+{
+       struct p9_mux_rpc *r;
+
+       P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);
+       r = a;
+       r->rcall = req->rcall;
+       r->err = req->err;
+
+       if (req->flush != None && !req->err)
+               r->err = -ERESTARTSYS;
+
+       wake_up(&r->wqueue);
+}
+
+/**
+ * p9_fd_rpc- sends 9P request and waits until a response is available.
+ *     The function can be interrupted.
+ * @m: mux data
+ * @tc: request to be sent
+ * @rc: pointer where a pointer to the response is stored
+ */
+int
+p9_fd_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc)
+{
+       struct p9_trans_fd *p = t->priv;
+       struct p9_conn *m = p->conn;
+       int err, sigpending;
+       unsigned long flags;
+       struct p9_req *req;
+       struct p9_mux_rpc r;
+
+       r.err = 0;
+       r.tcall = tc;
+       r.rcall = NULL;
+       r.m = m;
+       init_waitqueue_head(&r.wqueue);
+
+       if (rc)
+               *rc = NULL;
+
+       sigpending = 0;
+       if (signal_pending(current)) {
+               sigpending = 1;
+               clear_thread_flag(TIF_SIGPENDING);
+       }
+
+       req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
+               return err;
+       }
+
+       err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);
+       if (r.err < 0)
+               err = r.err;
+
+       if (err == -ERESTARTSYS && m->trans->status == Connected
+                                                       && m->err == 0) {
+               if (p9_mux_flush_request(m, req)) {
+                       /* wait until we get response of the flush message */
+                       do {
+                               clear_thread_flag(TIF_SIGPENDING);
+                               err = wait_event_interruptible(r.wqueue,
+                                       r.rcall || r.err);
+                       } while (!r.rcall && !r.err && err == -ERESTARTSYS &&
+                               m->trans->status == Connected && !m->err);
+
+                       err = -ERESTARTSYS;
+               }
+               sigpending = 1;
+       }
+
+       if (sigpending) {
+               spin_lock_irqsave(&current->sighand->siglock, flags);
+               recalc_sigpending();
+               spin_unlock_irqrestore(&current->sighand->siglock, flags);
+       }
+
+       if (rc)
+               *rc = r.rcall;
+       else
+               kfree(r.rcall);
+
+       p9_mux_free_request(m, req);
+       if (err > 0)
+               err = -EIO;
+
+       return err;
+}
+
+#ifdef P9_NONBLOCK
+/**
+ * p9_conn_rpcnb - sends 9P request without waiting for response.
+ * @m: mux data
+ * @tc: request to be sent
+ * @cb: callback function to be called when response arrives
+ * @cba: value to pass to the callback function
+ */
+int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
+                  p9_conn_req_callback cb, void *a)
+{
+       int err;
+       struct p9_req *req;
+
+       req = p9_send_request(m, tc, cb, a);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
+               return PTR_ERR(req);
+       }
+
+       P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
+       return 0;
+}
+#endif /* P9_NONBLOCK */
+
+/**
+ * p9_conn_cancel - cancel all pending requests with error
+ * @m: mux data
+ * @err: error code
+ */
+void p9_conn_cancel(struct p9_conn *m, int err)
+{
+       struct p9_req *req, *rtmp;
+       LIST_HEAD(cancel_list);
+
+       P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
+       m->err = err;
+       spin_lock(&m->lock);
+       list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
+               list_move(&req->req_list, &cancel_list);
+       }
+       list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
+               list_move(&req->req_list, &cancel_list);
+       }
+       spin_unlock(&m->lock);
+
+       list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
+               list_del(&req->req_list);
+               if (!req->err)
+                       req->err = err;
+
+               if (req->cb)
+                       (*req->cb) (req, req->cba);
+               else
+                       kfree(req->rcall);
+       }
+
+       wake_up(&m->equeue);
+}
+
 /**
  * v9fs_parse_options - parse mount options into session structure
  * @options: options string passed from mount
@@ -268,7 +1294,7 @@ end:
 }
 
 /**
- * p9_sock_close - shutdown socket
+ * p9_fd_close - shutdown socket
  * @trans: private socket structure
  *
  */
@@ -284,6 +1310,8 @@ static void p9_fd_close(struct p9_trans *trans)
        if (!ts)
                return;
 
+       p9_conn_destroy(ts->conn);
+
        trans->status = Disconnected;
        if (ts->rd)
                fput(ts->rd);
@@ -292,13 +1320,15 @@ static void p9_fd_close(struct p9_trans *trans)
        kfree(ts);
 }
 
-static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args)
+static struct p9_trans *
+p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu)
 {
        int err;
        struct p9_trans *trans;
        struct socket *csocket;
        struct sockaddr_in sin_server;
        struct p9_fd_opts opts;
+       struct p9_trans_fd *p;
 
        parse_opts(args, &opts);
 
@@ -306,11 +1336,10 @@ static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args)
        trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
        if (!trans)
                return ERR_PTR(-ENOMEM);
-
-       trans->write = p9_fd_write;
-       trans->read = p9_fd_read;
+       trans->msize = msize;
+       trans->extended = dotu;
+       trans->rpc = p9_fd_rpc;
        trans->close = p9_fd_close;
-       trans->poll = p9_fd_poll;
 
        sin_server.sin_family = AF_INET;
        sin_server.sin_addr.s_addr = in_aton(addr);
@@ -337,6 +1366,14 @@ static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args)
        if (err < 0)
                goto error;
 
+       p = (struct p9_trans_fd *) trans->priv;
+       p->conn = p9_conn_create(trans);
+       if (IS_ERR(p->conn)) {
+               err = PTR_ERR(p->conn);
+               p->conn = NULL;
+               goto error;
+       }
+
        return trans;
 
 error:
@@ -347,22 +1384,23 @@ error:
        return ERR_PTR(err);
 }
 
-static struct p9_trans *p9_trans_create_unix(const char *addr, char *args)
+static struct p9_trans *
+p9_trans_create_unix(const char *addr, char *args, int msize,
+                                                       unsigned char dotu)
 {
        int err;
        struct socket *csocket;
        struct sockaddr_un sun_server;
        struct p9_trans *trans;
+       struct p9_trans_fd *p;
 
        csocket = NULL;
        trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
        if (!trans)
                return ERR_PTR(-ENOMEM);
 
-       trans->write = p9_fd_write;
-       trans->read = p9_fd_read;
+       trans->rpc = p9_fd_rpc;
        trans->close = p9_fd_close;
-       trans->poll = p9_fd_poll;
 
        if (strlen(addr) > UNIX_PATH_MAX) {
                P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
@@ -387,6 +1425,16 @@ static struct p9_trans *p9_trans_create_unix(const char *addr, char *args)
        if (err < 0)
                goto error;
 
+       trans->msize = msize;
+       trans->extended = dotu;
+       p = (struct p9_trans_fd *) trans->priv;
+       p->conn = p9_conn_create(trans);
+       if (IS_ERR(p->conn)) {
+               err = PTR_ERR(p->conn);
+               p->conn = NULL;
+               goto error;
+       }
+
        return trans;
 
 error:
@@ -397,11 +1445,14 @@ error:
        return ERR_PTR(err);
 }
 
-static struct p9_trans *p9_trans_create_fd(const char *name, char *args)
+static struct p9_trans *
+p9_trans_create_fd(const char *name, char *args, int msize,
+                                                       unsigned char extended)
 {
        int err;
        struct p9_trans *trans;
        struct p9_fd_opts opts;
+       struct p9_trans_fd *p;
 
        parse_opts(args, &opts);
 
@@ -414,15 +1465,23 @@ static struct p9_trans *p9_trans_create_fd(const char *name, char *args)
        if (!trans)
                return ERR_PTR(-ENOMEM);
 
-       trans->write = p9_fd_write;
-       trans->read = p9_fd_read;
+       trans->rpc = p9_fd_rpc;
        trans->close = p9_fd_close;
-       trans->poll = p9_fd_poll;
 
        err = p9_fd_open(trans, opts.rfd, opts.wfd);
        if (err < 0)
                goto error;
 
+       trans->msize = msize;
+       trans->extended = extended;
+       p = (struct p9_trans_fd *) trans->priv;
+       p->conn = p9_conn_create(trans);
+       if (IS_ERR(p->conn)) {
+               err = PTR_ERR(p->conn);
+               p->conn = NULL;
+               goto error;
+       }
+
        return trans;
 
 error:
@@ -453,6 +1512,12 @@ static struct p9_trans_module p9_fd_trans = {
 
 static int __init p9_trans_fd_init(void)
 {
+       int ret = p9_mux_global_init();
+       if (ret) {
+               printk(KERN_WARNING "9p: starting mux failed\n");
+               return ret;
+       }
+
        v9fs_register_trans(&p9_tcp_trans);
        v9fs_register_trans(&p9_unix_trans);
        v9fs_register_trans(&p9_fd_trans);
@@ -460,13 +1525,7 @@ static int __init p9_trans_fd_init(void)
        return 1;
 }
 
-static void __exit p9_trans_fd_exit(void) {
-       printk(KERN_ERR "Removal of 9p transports not implemented\n");
-       BUG();
-}
-
 module_init(p9_trans_fd_init);
-module_exit(p9_trans_fd_exit);
 
 MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
 MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
index 42eea5fe262895587522ac689b1f06d2cf7ad7a1..0117b9fb8480d4a51830ff0e59a591a6ffeb2105 100644 (file)
@@ -1,17 +1,8 @@
 /*
  * The Guest 9p transport driver
  *
- * This is a trivial pipe-based transport driver based on the lguest console
- * code: we use lguest's DMA mechanism to send bytes out, and register a
- * DMA buffer to receive bytes in.  It is assumed to be present and available
- * from the very beginning of boot.
- *
- * This may be have been done by just instaniating another HVC console,
- * but HVC's blocksize of 16 bytes is annoying and painful to performance.
- *
- * A more efficient transport could be built based on the virtio block driver
- * but it requires some changes in the 9p transport model (which are in
- * progress)
+ * This is a block based transport driver based on the lguest block driver
+ * code.
  *
  */
 /*
 #include <linux/virtio.h>
 #include <linux/virtio_9p.h>
 
+#define VIRTQUEUE_NUM  128
+
 /* a single mutex to manage channel initialization and attachment */
 static DECLARE_MUTEX(virtio_9p_lock);
 /* global which tracks highest initialized channel */
 static int chan_index;
 
+#define P9_INIT_MAXTAG 16
+
+#define REQ_STATUS_IDLE        0
+#define REQ_STATUS_SENT 1
+#define REQ_STATUS_RCVD 2
+#define REQ_STATUS_FLSH 3
+
+struct p9_req_t {
+       int status;
+       wait_queue_head_t *wq;
+};
+
 /* We keep all per-channel information in a structure.
  * This structure is allocated within the devices dev->mem space.
  * A pointer to the structure will get put in the transport private.
@@ -68,146 +73,198 @@ static struct virtio_chan {
        bool initialized;               /* channel is initialized */
        bool inuse;                     /* channel is in use */
 
-       struct virtqueue *in_vq, *out_vq;
+       spinlock_t lock;
+
        struct virtio_device *vdev;
+       struct virtqueue *vq;
 
-       /* This is our input buffer, and how much data is left in it. */
-       unsigned int in_len;
-       char *in, *inbuf;
+       struct p9_idpool *tagpool;
+       struct p9_req_t *reqs;
+       int max_tag;
 
-       wait_queue_head_t wq;           /* waitq for buffer */
+       /* Scatterlist: can be too big for stack. */
+       struct scatterlist sg[VIRTQUEUE_NUM];
 } channels[MAX_9P_CHAN];
 
+/* Lookup requests by tag */
+static struct p9_req_t *p9_lookup_tag(struct virtio_chan *c, u16 tag)
+{
+       /* This looks up the original request by tag so we know which
+        * buffer to read the data into */
+       tag++;
+
+       while (tag >= c->max_tag) {
+               int old_max = c->max_tag;
+               int count;
+
+               if (c->max_tag)
+                       c->max_tag *= 2;
+               else
+                       c->max_tag = P9_INIT_MAXTAG;
+
+               c->reqs = krealloc(c->reqs, sizeof(struct p9_req_t)*c->max_tag,
+                                                               GFP_ATOMIC);
+               if (!c->reqs) {
+                       printk(KERN_ERR "Couldn't grow tag array\n");
+                       BUG();
+               }
+               for (count = old_max; count < c->max_tag; count++) {
+                       c->reqs[count].status = REQ_STATUS_IDLE;
+                       c->reqs[count].wq = kmalloc(sizeof(wait_queue_t),
+                                                               GFP_ATOMIC);
+                       if (!c->reqs[count].wq) {
+                               printk(KERN_ERR "Couldn't grow tag array\n");
+                               BUG();
+                       }
+                       init_waitqueue_head(c->reqs[count].wq);
+               }
+       }
+
+       return &c->reqs[tag];
+}
+
+
 /* How many bytes left in this page. */
 static unsigned int rest_of_page(void *data)
 {
        return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
 }
 
-static int p9_virtio_write(struct p9_trans *trans, void *buf, int count)
+static void p9_virtio_close(struct p9_trans *trans)
 {
-       struct virtio_chan *chan = (struct virtio_chan *) trans->priv;
-       struct virtqueue *out_vq = chan->out_vq;
-       struct scatterlist sg[1];
-       unsigned int len;
+       struct virtio_chan *chan = trans->priv;
+       int count;
+       unsigned int flags;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio write (%d)\n", count);
+       spin_lock_irqsave(&chan->lock, flags);
+       p9_idpool_destroy(chan->tagpool);
+       for (count = 0; count < chan->max_tag; count++)
+               kfree(chan->reqs[count].wq);
+       kfree(chan->reqs);
+       chan->max_tag = 0;
+       spin_unlock_irqrestore(&chan->lock, flags);
 
-       /* keep it simple - make sure we don't overflow a page */
-       if (rest_of_page(buf) < count)
-               count = rest_of_page(buf);
+       down(&virtio_9p_lock);
+       chan->inuse = false;
+       up(&virtio_9p_lock);
 
-       sg_init_one(sg, buf, count);
+       kfree(trans);
+}
 
-       /* add_buf wants a token to identify this buffer: we hand it any
-        * non-NULL pointer, since there's only ever one buffer. */
-       if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) == 0) {
-               /* Tell Host to go! */
-               out_vq->vq_ops->kick(out_vq);
-               /* Chill out until it's done with the buffer. */
-               while (!out_vq->vq_ops->get_buf(out_vq, &len))
-                       cpu_relax();
+static void req_done(struct virtqueue *vq)
+{
+       struct virtio_chan *chan = vq->vdev->priv;
+       struct p9_fcall *rc;
+       unsigned int len;
+       unsigned long flags;
+       struct p9_req_t *req;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) {
+               req = p9_lookup_tag(chan, rc->tag);
+               req->status = REQ_STATUS_RCVD;
+               wake_up(req->wq);
        }
-
-       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio wrote (%d)\n", count);
-
-       /* We're expected to return the amount of data we wrote: all of it. */
-       return count;
+       /* In case queue is stopped waiting for more buffers. */
+       spin_unlock_irqrestore(&chan->lock, flags);
 }
 
-/* Create a scatter-gather list representing our input buffer and put it in the
- * queue. */
-static void add_inbuf(struct virtio_chan *chan)
+static int
+pack_sg_list(struct scatterlist *sg, int start, int limit, char *data,
+                                                               int count)
 {
-       struct scatterlist sg[1];
-
-       sg_init_one(sg, chan->inbuf, PAGE_SIZE);
+       int s;
+       int index = start;
+
+       while (count) {
+               s = rest_of_page(data);
+               if (s > count)
+                       s = count;
+               sg_set_buf(&sg[index++], data, s);
+               count -= s;
+               data += s;
+               if (index > limit)
+                       BUG();
+       }
 
-       /* We should always be able to add one buffer to an empty queue. */
-       if (chan->in_vq->vq_ops->add_buf(chan->in_vq, sg, 0, 1, chan->inbuf))
-               BUG();
-       chan->in_vq->vq_ops->kick(chan->in_vq);
+       return index-start;
 }
 
-static int p9_virtio_read(struct p9_trans *trans, void *buf, int count)
+static int
+p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc)
 {
-       struct virtio_chan *chan = (struct virtio_chan *) trans->priv;
-       struct virtqueue *in_vq = chan->in_vq;
-
-       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio read (%d)\n", count);
+       int in, out;
+       int n, err, size;
+       struct virtio_chan *chan = t->priv;
+       char *rdata;
+       struct p9_req_t *req;
+       unsigned long flags;
+
+       if (*rc == NULL) {
+               *rc = kmalloc(sizeof(struct p9_fcall) + t->msize, GFP_KERNEL);
+               if (!*rc)
+                       return -ENOMEM;
+       }
 
-       /* If we don't have an input queue yet, we can't get input. */
-       BUG_ON(!in_vq);
+       rdata = (char *)*rc+sizeof(struct p9_fcall);
 
-       /* No buffer?  Try to get one. */
-       if (!chan->in_len) {
-               chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);
-               if (!chan->in)
-                       return 0;
+       n = P9_NOTAG;
+       if (tc->id != P9_TVERSION) {
+               n = p9_idpool_get(chan->tagpool);
+               if (n < 0)
+                       return -ENOMEM;
        }
 
-       /* You want more than we have to give?  Well, try wanting less! */
-       if (chan->in_len < count)
-               count = chan->in_len;
+       spin_lock_irqsave(&chan->lock, flags);
+       req = p9_lookup_tag(chan, n);
+       spin_unlock_irqrestore(&chan->lock, flags);
 
-       /* Copy across to their buffer and increment offset. */
-       memcpy(buf, chan->in, count);
-       chan->in += count;
-       chan->in_len -= count;
+       p9_set_tag(tc, n);
 
-       /* Finished?  Re-register buffer so Host will use it again. */
-       if (chan->in_len == 0)
-               add_inbuf(chan);
+       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc tag %d\n", n);
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio finished read (%d)\n",
-                                                                       count);
+       out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, tc->sdata, tc->size);
+       in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, t->msize);
 
-       return count;
-}
+       req->status = REQ_STATUS_SENT;
 
-/* The poll function is used by 9p transports to determine if there
- * is there is activity available on a particular channel.  In our case
- * we use it to wait for a callback from the input routines.
- */
-static unsigned int
-p9_virtio_poll(struct p9_trans *trans, struct poll_table_struct *pt)
-{
-       struct virtio_chan *chan = (struct virtio_chan *)trans->priv;
-       struct virtqueue *in_vq = chan->in_vq;
-       int ret = POLLOUT; /* we can always handle more output */
+       if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, tc)) {
+               P9_DPRINTK(P9_DEBUG_TRANS,
+                       "9p debug: virtio rpc add_buf returned failure");
+               return -EIO;
+       }
 
-       poll_wait(NULL, &chan->wq, pt);
+       chan->vq->vq_ops->kick(chan->vq);
 
-       /* No buffer?  Try to get one. */
-       if (!chan->in_len)
-               chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);
+       wait_event(*req->wq, req->status == REQ_STATUS_RCVD);
 
-       if (chan->in_len)
-               ret |= POLLIN;
+       size = le32_to_cpu(*(__le32 *) rdata);
 
-       return ret;
-}
+       err = p9_deserialize_fcall(rdata, size, *rc, t->extended);
+       if (err < 0) {
+               P9_DPRINTK(P9_DEBUG_TRANS,
+                       "9p debug: virtio rpc deserialize returned %d\n", err);
+               return err;
+       }
 
-static void p9_virtio_close(struct p9_trans *trans)
-{
-       struct virtio_chan *chan = trans->priv;
+#ifdef CONFIG_NET_9P_DEBUG
+       if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
+               char buf[150];
 
-       down(&virtio_9p_lock);
-       chan->inuse = false;
-       up(&virtio_9p_lock);
+               p9_printfcall(buf, sizeof(buf), *rc, t->extended);
+               printk(KERN_NOTICE ">>> %p %s\n", t, buf);
+       }
+#endif
 
-       kfree(trans);
-}
+       if (n != P9_NOTAG && p9_idpool_check(n, chan->tagpool))
+               p9_idpool_put(n, chan->tagpool);
 
-static void p9_virtio_intr(struct virtqueue *q)
-{
-       struct virtio_chan *chan = q->vdev->priv;
+       req->status = REQ_STATUS_IDLE;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "9p poll_wakeup: %p\n", &chan->wq);
-       wake_up_interruptible(&chan->wq);
+       return 0;
 }
 
-static int p9_virtio_probe(struct virtio_device *dev)
+static int p9_virtio_probe(struct virtio_device *vdev)
 {
        int err;
        struct virtio_chan *chan;
@@ -221,44 +278,29 @@ static int p9_virtio_probe(struct virtio_device *dev)
        if (chan_index > MAX_9P_CHAN) {
                printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
                BUG();
-       }
-
-       chan->vdev = dev;
-
-       /* This is the scratch page we use to receive console input */
-       chan->inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!chan->inbuf) {
                err = -ENOMEM;
                goto fail;
        }
 
-       /* Find the input queue. */
-       dev->priv = chan;
-       chan->in_vq = dev->config->find_vq(dev, 0, p9_virtio_intr);
-       if (IS_ERR(chan->in_vq)) {
-               err = PTR_ERR(chan->in_vq);
-               goto free;
-       }
+       chan->vdev = vdev;
 
-       chan->out_vq = dev->config->find_vq(dev, 1, NULL);
-       if (IS_ERR(chan->out_vq)) {
-               err = PTR_ERR(chan->out_vq);
-               goto free_in_vq;
+       /* We expect one virtqueue, for requests. */
+       chan->vq = vdev->config->find_vq(vdev, 0, req_done);
+       if (IS_ERR(chan->vq)) {
+               err = PTR_ERR(chan->vq);
+               goto out_free_vq;
        }
+       chan->vq->vdev->priv = chan;
+       spin_lock_init(&chan->lock);
 
-       init_waitqueue_head(&chan->wq);
+       sg_init_table(chan->sg, VIRTQUEUE_NUM);
 
-       /* Register the input buffer the first time. */
-       add_inbuf(chan);
        chan->inuse = false;
        chan->initialized = true;
-
        return 0;
 
-free_in_vq:
-       dev->config->del_vq(chan->in_vq);
-free:
-       kfree(chan->inbuf);
+out_free_vq:
+       vdev->config->del_vq(chan->vq);
 fail:
        down(&virtio_9p_lock);
        chan_index--;
@@ -271,11 +313,13 @@ fail:
  * alternate channels by matching devname versus a virtio_config entry.
  * We use a simple reference count mechanism to ensure that only a single
  * mount has a channel open at a time. */
-static struct p9_trans *p9_virtio_create(const char *devname, char *args)
+static struct p9_trans *
+p9_virtio_create(const char *devname, char *args, int msize,
+                                                       unsigned char extended)
 {
        struct p9_trans *trans;
-       int index = 0;
        struct virtio_chan *chan = channels;
+       int index = 0;
 
        down(&virtio_9p_lock);
        while (index < MAX_9P_CHAN) {
@@ -290,25 +334,45 @@ static struct p9_trans *p9_virtio_create(const char *devname, char *args)
        up(&virtio_9p_lock);
 
        if (index >= MAX_9P_CHAN) {
-               printk(KERN_ERR "9p: virtio: couldn't find a free channel\n");
-               return NULL;
+               printk(KERN_ERR "9p: no channels available\n");
+               return ERR_PTR(-ENODEV);
        }
 
+       chan->tagpool = p9_idpool_create();
+       if (IS_ERR(chan->tagpool)) {
+               printk(KERN_ERR "9p: couldn't allocate tagpool\n");
+               return ERR_PTR(-ENOMEM);
+       }
+       p9_idpool_get(chan->tagpool); /* reserve tag 0 */
+       chan->max_tag = 0;
+       chan->reqs = NULL;
+
        trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
        if (!trans) {
                printk(KERN_ERR "9p: couldn't allocate transport\n");
                return ERR_PTR(-ENOMEM);
        }
-
-       trans->write = p9_virtio_write;
-       trans->read = p9_virtio_read;
+       trans->extended = extended;
+       trans->msize = msize;
        trans->close = p9_virtio_close;
-       trans->poll = p9_virtio_poll;
+       trans->rpc = p9_virtio_rpc;
        trans->priv = chan;
 
        return trans;
 }
 
+static void p9_virtio_remove(struct virtio_device *vdev)
+{
+       struct virtio_chan *chan = vdev->priv;
+
+       BUG_ON(chan->inuse);
+
+       if (chan->initialized) {
+               vdev->config->del_vq(chan->vq);
+               chan->initialized = false;
+       }
+}
+
 #define VIRTIO_ID_9P 9
 
 static struct virtio_device_id id_table[] = {
@@ -322,12 +386,13 @@ static struct virtio_driver p9_virtio_drv = {
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
        .probe =        p9_virtio_probe,
+       .remove =       p9_virtio_remove,
 };
 
 static struct p9_trans_module p9_virtio_trans = {
        .name = "virtio",
        .create = p9_virtio_create,
-       .maxsize = PAGE_SIZE,
+       .maxsize = PAGE_SIZE*16,
        .def = 0,
 };
 
@@ -343,7 +408,13 @@ static int __init p9_virtio_init(void)
        return register_virtio_driver(&p9_virtio_drv);
 }
 
+static void __exit p9_virtio_cleanup(void)
+{
+       unregister_virtio_driver(&p9_virtio_drv);
+}
+
 module_init(p9_virtio_init);
+module_exit(p9_virtio_cleanup);
 
 MODULE_DEVICE_TABLE(virtio, id_table);
 MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
index 22077b79395d377f7b4e54e189391531895a7d72..ef7215565d881de05e00c7214623f3a8fa759b8f 100644 (file)
@@ -33,7 +33,7 @@
 #include <net/9p/9p.h>
 
 struct p9_idpool {
-       struct semaphore lock;
+       spinlock_t lock;
        struct idr pool;
 };
 
@@ -45,7 +45,7 @@ struct p9_idpool *p9_idpool_create(void)
        if (!p)
                return ERR_PTR(-ENOMEM);
 
-       init_MUTEX(&p->lock);
+       spin_lock_init(&p->lock);
        idr_init(&p->pool);
 
        return p;
@@ -71,19 +71,17 @@ int p9_idpool_get(struct p9_idpool *p)
 {
        int i = 0;
        int error;
+       unsigned int flags;
 
 retry:
        if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
                return 0;
 
-       if (down_interruptible(&p->lock) == -EINTR) {
-               P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
-               return -1;
-       }
+       spin_lock_irqsave(&p->lock, flags);
 
        /* no need to store exactly p, we just need something non-null */
        error = idr_get_new(&p->pool, p, &i);
-       up(&p->lock);
+       spin_unlock_irqrestore(&p->lock, flags);
 
        if (error == -EAGAIN)
                goto retry;
@@ -104,12 +102,10 @@ EXPORT_SYMBOL(p9_idpool_get);
 
 void p9_idpool_put(int id, struct p9_idpool *p)
 {
-       if (down_interruptible(&p->lock) == -EINTR) {
-               P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
-               return;
-       }
+       unsigned int flags;
+       spin_lock_irqsave(&p->lock, flags);
        idr_remove(&p->pool, id);
-       up(&p->lock);
+       spin_unlock_irqrestore(&p->lock, flags);
 }
 EXPORT_SYMBOL(p9_idpool_put);
 
index 749fa044eca53cb6ecda61e8019045d04705973c..85c680add6dfd1fe23cc997265b68eb8ca9b309f 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/net.h>
 
 #include <net/ip_vs.h>
 
@@ -169,7 +170,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                                 */
                                if (mark->cw == 0) {
                                        mark->cl = &svc->destinations;
-                                       IP_VS_INFO("ip_vs_wrr_schedule(): "
+                                       IP_VS_ERR_RL("ip_vs_wrr_schedule(): "
                                                   "no available servers\n");
                                        dest = NULL;
                                        goto out;
index e77592d050ce8a33a777ab12e6c384b84bc524b1..45c7c0c3875e808beb1ad1085a213955d6ca8235 100644 (file)
@@ -1,6 +1,5 @@
 config MAC80211
        tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
-       depends on EXPERIMENTAL
        select CRYPTO
        select CRYPTO_ECB
        select CRYPTO_ARC4
index 5e82f1c0afbbee2120f489447ae4b7092e7aed18..2d0c29c837f72d3308242d4d30fd0f038ca4af57 100644 (file)
@@ -239,7 +239,7 @@ static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock,
        /* find a remote transport endpoint from the local one */
        peer = rxrpc_get_peer(srx, gfp);
        if (IS_ERR(peer))
-               return ERR_PTR(PTR_ERR(peer));
+               return ERR_CAST(peer);
 
        /* find a transport */
        trans = rxrpc_get_transport(rx->local, peer, gfp);
@@ -282,7 +282,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
                trans = rxrpc_name_to_transport(sock, (struct sockaddr *) srx,
                                                sizeof(*srx), 0, gfp);
                if (IS_ERR(trans)) {
-                       call = ERR_PTR(PTR_ERR(trans));
+                       call = ERR_CAST(trans);
                        trans = NULL;
                        goto out;
                }
@@ -306,7 +306,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
 
        bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);
        if (IS_ERR(bundle)) {
-               call = ERR_PTR(PTR_ERR(bundle));
+               call = ERR_CAST(bundle);
                goto out;
        }
 
index 8d7698621f0a0245deca1f17709ee9377d5dcdd6..971b867e0484fd8d50ec0d60e56109e8f54b02f4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <linux/if_vlan.h>
 
 #include <net/pkt_cls.h>
 #include <net/ip.h>
@@ -270,6 +271,15 @@ static u32 flow_get_skgid(const struct sk_buff *skb)
        return 0;
 }
 
+static u32 flow_get_vlan_tag(const struct sk_buff *skb)
+{
+       u16 uninitialized_var(tag);
+
+       if (vlan_get_tag(skb, &tag) < 0)
+               return 0;
+       return tag & VLAN_VID_MASK;
+}
+
 static u32 flow_key_get(const struct sk_buff *skb, int key)
 {
        switch (key) {
@@ -305,6 +315,8 @@ static u32 flow_key_get(const struct sk_buff *skb, int key)
                return flow_get_skuid(skb);
        case FLOW_KEY_SKGID:
                return flow_get_skgid(skb);
+       case FLOW_KEY_VLAN_TAG:
+               return flow_get_vlan_tag(skb);
        default:
                WARN_ON(1);
                return 0;
@@ -402,12 +414,13 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
 
        if (tb[TCA_FLOW_KEYS]) {
                keymask = nla_get_u32(tb[TCA_FLOW_KEYS]);
-               if (fls(keymask) - 1 > FLOW_KEY_MAX)
-                       return -EOPNOTSUPP;
 
                nkeys = hweight32(keymask);
                if (nkeys == 0)
                        return -EINVAL;
+
+               if (fls(keymask) - 1 > FLOW_KEY_MAX)
+                       return -EOPNOTSUPP;
        }
 
        err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map);
index 9c2ec1992a2a0f8a95d21957c1171ab06f59959c..2a7e648fbcf44edd7ce7944fee7627f3590d434a 100644 (file)
@@ -176,7 +176,7 @@ META_COLLECTOR(var_dev)
 
 META_COLLECTOR(int_vlan_tag)
 {
-       unsigned short tag;
+       unsigned short uninitialized_var(tag);
        if (vlan_get_tag(skb, &tag) < 0)
                *err = -1;
        else
index d716b76098bb670d76abff1eeff9830ff88ebfbc..340ad6920511aa08a52f5360c54836c682e2deed 100755 (executable)
@@ -2,7 +2,7 @@
 
 #      Check the stack usage of functions
 #
-#      Copyright Joern Engel <joern@wh.fh-wedel.de>
+#      Copyright Joern Engel <joern@lazybastard.org>
 #      Inspired by Linus Torvalds
 #      Original idea maybe from Keith Owens
 #      s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
index 1f11d848532a0474b342ca462a905af4f044b2f6..c912137f80e247d0b8076e32f7386005127889a0 100644 (file)
 
 #define KSYM_NAME_LEN          128
 
-
 struct sym_entry {
        unsigned long long addr;
        unsigned int len;
+       unsigned int start_pos;
        unsigned char *sym;
 };
 
-
 static struct sym_entry *table;
 static unsigned int table_size, table_cnt;
-static unsigned long long _text, _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
+static unsigned long long _text, _stext, _etext, _sinittext, _einittext;
 static int all_symbols = 0;
 static char symbol_prefix_char = '\0';
 
@@ -99,10 +98,6 @@ static int read_symbol(FILE *in, struct sym_entry *s)
                _sinittext = s->addr;
        else if (strcmp(sym, "_einittext") == 0)
                _einittext = s->addr;
-       else if (strcmp(sym, "_sextratext") == 0)
-               _sextratext = s->addr;
-       else if (strcmp(sym, "_eextratext") == 0)
-               _eextratext = s->addr;
        else if (toupper(stype) == 'A')
        {
                /* Keep these useful absolute symbols */
@@ -165,18 +160,18 @@ static int symbol_valid(struct sym_entry *s)
         * and inittext sections are discarded */
        if (!all_symbols) {
                if ((s->addr < _stext || s->addr > _etext)
-                   && (s->addr < _sinittext || s->addr > _einittext)
-                   && (s->addr < _sextratext || s->addr > _eextratext))
+                   && (s->addr < _sinittext || s->addr > _einittext))
                        return 0;
                /* Corner case.  Discard any symbols with the same value as
-                * _etext _einittext or _eextratext; they can move between pass
-                * 1 and 2 when the kallsyms data are added.  If these symbols
-                * move then they may get dropped in pass 2, which breaks the
-                * kallsyms rules.
+                * _etext _einittext; they can move between pass 1 and 2 when
+                * the kallsyms data are added.  If these symbols move then
+                * they may get dropped in pass 2, which breaks the kallsyms
+                * rules.
                 */
-               if ((s->addr == _etext && strcmp((char*)s->sym + offset, "_etext")) ||
-                   (s->addr == _einittext && strcmp((char*)s->sym + offset, "_einittext")) ||
-                   (s->addr == _eextratext && strcmp((char*)s->sym + offset, "_eextratext")))
+               if ((s->addr == _etext &&
+                               strcmp((char *)s->sym + offset, "_etext")) ||
+                   (s->addr == _einittext &&
+                               strcmp((char *)s->sym + offset, "_einittext")))
                        return 0;
        }
 
@@ -202,8 +197,10 @@ static void read_map(FILE *in)
                                exit (1);
                        }
                }
-               if (read_symbol(in, &table[table_cnt]) == 0)
+               if (read_symbol(in, &table[table_cnt]) == 0) {
+                       table[table_cnt].start_pos = table_cnt;
                        table_cnt++;
+               }
        }
 }
 
@@ -506,6 +503,35 @@ static void optimize_token_table(void)
        optimize_result();
 }
 
+static int compare_symbols(const void *a, const void *b)
+{
+       const struct sym_entry *sa;
+       const struct sym_entry *sb;
+       int wa, wb;
+
+       sa = a;
+       sb = b;
+
+       /* sort by address first */
+       if (sa->addr > sb->addr)
+               return 1;
+       if (sa->addr < sb->addr)
+               return -1;
+
+       /* sort by "weakness" type */
+       wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W');
+       wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W');
+       if (wa != wb)
+               return wa - wb;
+
+       /* sort by initial order, so that other symbols are left undisturbed */
+       return sa->start_pos - sb->start_pos;
+}
+
+static void sort_symbols(void)
+{
+       qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols);
+}
 
 int main(int argc, char **argv)
 {
@@ -527,6 +553,7 @@ int main(int argc, char **argv)
                usage();
 
        read_map(stdin);
+       sort_symbols();
        optimize_token_table();
        write_src();
 
index ec54f12f57b04c10b6f24f7aa561afccb3fba0b7..6c18a14386a4da0a467fe8832c2d7b60c08430ea 100755 (executable)
@@ -218,6 +218,7 @@ sub usage {
     print "         [ -function funcname [ -function funcname ...] ]\n";
     print "         [ -nofunction funcname [ -nofunction funcname ...] ]\n";
     print "         c source file(s) > outputfile\n";
+    print "         -v : verbose output, more warnings & other info listed\n";
     exit 1;
 }
 
@@ -1654,7 +1655,7 @@ sub dump_function($$) {
        $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
        $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
        $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
        $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
        $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
        $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
@@ -1881,6 +1882,13 @@ sub process_file($) {
                } else {
                    $declaration_purpose = "";
                }
+
+               if (($declaration_purpose eq "") && $verbose) {
+                       print STDERR "Warning(${file}:$.): missing initial short description on line:\n";
+                       print STDERR $_;
+                       ++$warnings;
+               }
+
                if ($identifier =~ m/^struct/) {
                    $decl_type = 'struct';
                } elsif ($identifier =~ m/^union/) {
@@ -1907,7 +1915,7 @@ sub process_file($) {
                $newsection = $1;
                $newcontents = $2;
 
-               if ($contents ne "") {
+               if (($contents ne "") && ($contents ne "\n")) {
                    if (!$in_doc_sect && $verbose) {
                        print STDERR "Warning(${file}:$.): contents before sections\n";
                        ++$warnings;
index 25ffe1b9dc98467d7be1ec373c7024f246172e0b..5dfc206748cfbd76f2e1f3114515aba7294cf67c 100644 (file)
@@ -104,6 +104,24 @@ config SECURITY_ROOTPLUG
          
          If you are unsure how to answer this question, answer N.
 
+config SECURITY_DEFAULT_MMAP_MIN_ADDR
+        int "Low address space to protect from user allocation"
+        depends on SECURITY
+        default 0
+        help
+         This is the portion of low virtual memory which should be protected
+         from userspace allocation.  Keeping a user from writing to low pages
+         can help reduce the impact of kernel NULL pointer bugs.
+
+         For most users with lots of address space a value of 65536 is
+         reasonable and should cause no problems.  Programs which use vm86
+         functionality would either need additional permissions from either
+         the LSM or the capabilities module or have this protection disabled.
+
+         This value can be changed after boot using the
+         /proc/sys/vm/mmap_min_addr tunable.
+
+
 source security/selinux/Kconfig
 source security/smack/Kconfig
 
index fdd5ca6d89fc1680975604d28ffa261398c650a6..654d23baf3525ceee6134f75039a4d450fc1edd9 100644 (file)
@@ -820,7 +820,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        key = key_alloc(ktype, description, current->fsuid, current->fsgid,
                        current, perm, flags);
        if (IS_ERR(key)) {
-               key_ref = ERR_PTR(PTR_ERR(key));
+               key_ref = ERR_CAST(key);
                goto error_3;
        }
 
index 2a0eb946fc7ee84f95b7b32cc39149c8e510a2f5..c886a2bb792ae034950ec71aa20af5fd1d4c17ee 100644 (file)
@@ -660,7 +660,7 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
 
                key = key_lookup(id);
                if (IS_ERR(key)) {
-                       key_ref = ERR_PTR(PTR_ERR(key));
+                       key_ref = ERR_CAST(key);
                        goto error;
                }
 
index 6381e616c47744904b6efe0f412b0039289bec7d..5ecc5057fb542c1bb9f914e72f4b95695d05dd70 100644 (file)
@@ -389,7 +389,7 @@ struct key *request_key_and_link(struct key_type *type,
        if (!IS_ERR(key_ref)) {
                key = key_ref_to_ptr(key_ref);
        } else if (PTR_ERR(key_ref) != -EAGAIN) {
-               key = ERR_PTR(PTR_ERR(key_ref));
+               key = ERR_CAST(key_ref);
        } else  {
                /* the search failed, but the keyrings were searchable, so we
                 * should consult userspace if we can */
index 510f7be73a2d4e954cc8de34bed9580e5cc4a47b..e42b5252486fe07eb623f413ec61cc7073758da8 100644 (file)
@@ -261,7 +261,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
                current);
 
        if (IS_ERR(authkey_ref)) {
-               authkey = ERR_PTR(PTR_ERR(authkey_ref));
+               authkey = ERR_CAST(authkey_ref);
                goto error;
        }
 
index b6c57a6b2ff55d41ca660b232b8bcd95dbd7faed..d15e56cbaadeea25c550cfc985de2dbbfbf410fa 100644 (file)
@@ -23,7 +23,9 @@ extern struct security_operations dummy_security_ops;
 extern void security_fixup_ops(struct security_operations *ops);
 
 struct security_operations *security_ops;      /* Initialized to NULL */
-unsigned long mmap_min_addr;           /* 0 means no protection */
+
+/* amount of vm to protect from userspace access */
+unsigned long mmap_min_addr = CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR;
 
 static inline int verify(struct security_operations *ops)
 {
index 23137c17f917a0727dd79a99bcad900c308c387a..837ce420d2f64ff810c4e96b7b7ce9a1ca695328 100644 (file)
@@ -107,7 +107,6 @@ int security_get_classes(char ***classes, int *nclasses);
 int security_get_permissions(char *class, char ***perms, int *nperms);
 int security_get_reject_unknown(void);
 int security_get_allow_unknown(void);
-int security_get_policycaps(int *len, int **values);
 
 #define SECURITY_FS_USE_XATTR          1 /* use xattr */
 #define SECURITY_FS_USE_TRANS          2 /* use transition SIDs, e.g. devpts/tmpfs */
index fced6bccee760b87d98df5b0a26133b6ae0b655c..f374186012151e42ba197ac80391a147fb3821f7 100644 (file)
@@ -2245,39 +2245,6 @@ int security_get_allow_unknown(void)
        return policydb.allow_unknown;
 }
 
-/**
- * security_get_policycaps - Query the loaded policy for its capabilities
- * @len: the number of capability bits
- * @values: the capability bit array
- *
- * Description:
- * Get an array of the policy capabilities in @values where each entry in
- * @values is either true (1) or false (0) depending the policy's support of
- * that feature.  The policy capabilities are defined by the
- * POLICYDB_CAPABILITY_* enums.  The size of the array is stored in @len and it
- * is up to the caller to free the array in @values.  Returns zero on success,
- * negative values on failure.
- *
- */
-int security_get_policycaps(int *len, int **values)
-{
-       int rc = -ENOMEM;
-       unsigned int iter;
-
-       POLICY_RDLOCK;
-
-       *values = kcalloc(POLICYDB_CAPABILITY_MAX, sizeof(int), GFP_ATOMIC);
-       if (*values == NULL)
-               goto out;
-       for (iter = 0; iter < POLICYDB_CAPABILITY_MAX; iter++)
-               (*values)[iter] = ebitmap_get_bit(&policydb.policycaps, iter);
-       *len = POLICYDB_CAPABILITY_MAX;
-
-out:
-       POLICY_RDUNLOCK;
-       return rc;
-}
-
 /**
  * security_policycap_supported - Check for a specific policy capability
  * @req_cap: capability
index f883c4b676abaed9ca308376b032d8fbdbd37903..1f86299fae409a297154737002f4466782cc597f 100644 (file)
@@ -6,7 +6,6 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_SOUND_OSS)                += sound.o
-obj-$(CONFIG_SOUND_CS4232)     += cs4232.o ad1848.o 
 
 # Please leave it as is, cause the link order is significant !
 
@@ -16,7 +15,6 @@ obj-$(CONFIG_SOUND_AEDSP16)   += aedsp16.o
 obj-$(CONFIG_SOUND_PSS)                += pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)       += trix.o ad1848.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_SSCAPE)     += sscape.o ad1848.o mpu401.o
-obj-$(CONFIG_SOUND_CS4232)     += cs4232.o uart401.o
 obj-$(CONFIG_SOUND_MSS)                += ad1848.o
 obj-$(CONFIG_SOUND_PAS)                += pas2.o sb.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_SB)         += sb.o sb_lib.o uart401.o
@@ -27,19 +25,12 @@ obj-$(CONFIG_SOUND_YM3812)  += opl3.o
 obj-$(CONFIG_SOUND_VMIDI)      += v_midi.o
 obj-$(CONFIG_SOUND_VIDC)       += vidc_mod.o
 obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
-
-obj-$(CONFIG_SOUND_VIA82CXXX)  += via82cxxx_audio.o ac97_codec.o
-ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
-  obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o
-endif
 obj-$(CONFIG_SOUND_MSNDCLAS)   += msnd.o msnd_classic.o
 obj-$(CONFIG_SOUND_MSNDPIN)    += msnd.o msnd_pinnacle.o
 obj-$(CONFIG_SOUND_VWSND)      += vwsnd.o
-obj-$(CONFIG_SOUND_ICH)                += i810_audio.o ac97_codec.o
 obj-$(CONFIG_SOUND_AU1550_AC97)        += au1550_ac97.o ac97_codec.o
 obj-$(CONFIG_SOUND_TRIDENT)    += trident.o ac97_codec.o
 obj-$(CONFIG_SOUND_BCM_CS4297A)        += swarm_cs4297a.o
-obj-$(CONFIG_SOUND_BT878)      += btaudio.o
 
 obj-$(CONFIG_SOUND_WM97XX)     += ac97_plugin_wm97xx.o
 
index fef56cac06c832650db596299af04185dc9919dc..87a672680761305330366b68091877db6cdbc544 100644 (file)
@@ -189,42 +189,6 @@ static const struct {
        {0x57454301, "Winbond 83971D",          &null_ops},
 };
 
-static const char *ac97_stereo_enhancements[] =
-{
-       /*   0 */ "No 3D Stereo Enhancement",
-       /*   1 */ "Analog Devices Phat Stereo",
-       /*   2 */ "Creative Stereo Enhancement",
-       /*   3 */ "National Semi 3D Stereo Enhancement",
-       /*   4 */ "YAMAHA Ymersion",
-       /*   5 */ "BBE 3D Stereo Enhancement",
-       /*   6 */ "Crystal Semi 3D Stereo Enhancement",
-       /*   7 */ "Qsound QXpander",
-       /*   8 */ "Spatializer 3D Stereo Enhancement",
-       /*   9 */ "SRS 3D Stereo Enhancement",
-       /*  10 */ "Platform Tech 3D Stereo Enhancement",
-       /*  11 */ "AKM 3D Audio",
-       /*  12 */ "Aureal Stereo Enhancement",
-       /*  13 */ "Aztech 3D Enhancement",
-       /*  14 */ "Binaura 3D Audio Enhancement",
-       /*  15 */ "ESS Technology Stereo Enhancement",
-       /*  16 */ "Harman International VMAx",
-       /*  17 */ "Nvidea 3D Stereo Enhancement",
-       /*  18 */ "Philips Incredible Sound",
-       /*  19 */ "Texas Instruments 3D Stereo Enhancement",
-       /*  20 */ "VLSI Technology 3D Stereo Enhancement",
-       /*  21 */ "TriTech 3D Stereo Enhancement",
-       /*  22 */ "Realtek 3D Stereo Enhancement",
-       /*  23 */ "Samsung 3D Stereo Enhancement",
-       /*  24 */ "Wolfson Microelectronics 3D Enhancement",
-       /*  25 */ "Delta Integration 3D Enhancement",
-       /*  26 */ "SigmaTel 3D Enhancement",
-       /*  27 */ "Winbond 3D Stereo Enhancement",
-       /*  28 */ "Rockwell 3D Stereo Enhancement",
-       /*  29 */ "Reserved 29",
-       /*  30 */ "Reserved 30",
-       /*  31 */ "Reserved 31"
-};
-
 /* this table has default mixer values for all OSS mixers. */
 static struct mixer_defaults {
        int mixer;
@@ -614,83 +578,6 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned
        return -EINVAL;
 }
 
-/* entry point for /proc/driver/controller_vendor/ac97/%d */
-int ac97_read_proc (char *page, char **start, off_t off,
-                   int count, int *eof, void *data)
-{
-       int len = 0, cap, extid, val, id1, id2;
-       struct ac97_codec *codec;
-       int is_ac97_20 = 0;
-
-       if ((codec = data) == NULL)
-               return -ENODEV;
-
-       id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
-       id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
-       len += sprintf (page+len, "Vendor name      : %s\n", codec->name);
-       len += sprintf (page+len, "Vendor id        : %04X %04X\n", id1, id2);
-
-       extid = codec->codec_read(codec, AC97_EXTENDED_ID);
-       extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13));
-       len += sprintf (page+len, "AC97 Version     : %s\n",
-                       extid ? "2.0 or later" : "1.0");
-       if (extid) is_ac97_20 = 1;
-
-       cap = codec->codec_read(codec, AC97_RESET);
-       len += sprintf (page+len, "Capabilities     :%s%s%s%s%s%s\n",
-                       cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",
-                       cap & 0x0002 ? " -reserved1-" : "",
-                       cap & 0x0004 ? " -bass & treble-" : "",
-                       cap & 0x0008 ? " -simulated stereo-" : "",
-                       cap & 0x0010 ? " -headphone out-" : "",
-                       cap & 0x0020 ? " -loudness-" : "");
-       val = cap & 0x00c0;
-       len += sprintf (page+len, "DAC resolutions  :%s%s%s\n",
-                       " -16-bit-",
-                       val & 0x0040 ? " -18-bit-" : "",
-                       val & 0x0080 ? " -20-bit-" : "");
-       val = cap & 0x0300;
-       len += sprintf (page+len, "ADC resolutions  :%s%s%s\n",
-                       " -16-bit-",
-                       val & 0x0100 ? " -18-bit-" : "",
-                       val & 0x0200 ? " -20-bit-" : "");
-       len += sprintf (page+len, "3D enhancement   : %s\n",
-                       ac97_stereo_enhancements[(cap >> 10) & 0x1f]);
-
-       val = codec->codec_read(codec, AC97_GENERAL_PURPOSE);
-       len += sprintf (page+len, "POP path         : %s 3D\n"
-                       "Sim. stereo      : %s\n"
-                       "3D enhancement   : %s\n"
-                       "Loudness         : %s\n"
-                       "Mono output      : %s\n"
-                       "MIC select       : %s\n"
-                       "ADC/DAC loopback : %s\n",
-                       val & 0x8000 ? "post" : "pre",
-                       val & 0x4000 ? "on" : "off",
-                       val & 0x2000 ? "on" : "off",
-                       val & 0x1000 ? "on" : "off",
-                       val & 0x0200 ? "MIC" : "MIX",
-                       val & 0x0100 ? "MIC2" : "MIC1",
-                       val & 0x0080 ? "on" : "off");
-
-       extid = codec->codec_read(codec, AC97_EXTENDED_ID);
-       cap = extid;
-       len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n",
-                       cap & 0x0001 ? " -var rate PCM audio-" : "",
-                       cap & 0x0002 ? " -2x PCM audio out-" : "",
-                       cap & 0x0008 ? " -var rate MIC in-" : "",
-                       cap & 0x0040 ? " -PCM center DAC-" : "",
-                       cap & 0x0080 ? " -PCM surround DAC-" : "",
-                       cap & 0x0100 ? " -PCM LFE DAC-" : "",
-                       cap & 0x0200 ? " -slot/DAC mappings-" : "");
-       if (is_ac97_20) {
-               len += sprintf (page+len, "Front DAC rate   : %d\n",
-                               codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE));
-       }
-
-       return len;
-}
-
 /**
  *     codec_id        -  Turn id1/id2 into a PnP string
  *     @id1: Vendor ID1
@@ -1313,176 +1200,5 @@ static int pt101_init(struct ac97_codec * codec)
 #endif
        
 
-EXPORT_SYMBOL(ac97_read_proc);
 EXPORT_SYMBOL(ac97_probe_codec);
 
-/*
- *     AC97 library support routines
- */    
-/**
- *     ac97_set_dac_rate       -       set codec rate adaption
- *     @codec: ac97 code
- *     @rate: rate in hertz
- *
- *     Set the DAC rate. Assumes the codec supports VRA. The caller is
- *     expected to have checked this little detail.
- */
-unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate)
-{
-       unsigned int new_rate = rate;
-       u32 dacp;
-       u32 mast_vol, phone_vol, mono_vol, pcm_vol;
-       u32 mute_vol = 0x8000;  /* The mute volume? */
-
-       if(rate != codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE))
-       {
-               /* Mute several registers */
-               mast_vol = codec->codec_read(codec, AC97_MASTER_VOL_STEREO);
-               mono_vol = codec->codec_read(codec, AC97_MASTER_VOL_MONO);
-               phone_vol = codec->codec_read(codec, AC97_HEADPHONE_VOL);
-               pcm_vol = codec->codec_read(codec, AC97_PCMOUT_VOL);
-               codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mute_vol);
-               codec->codec_write(codec, AC97_MASTER_VOL_MONO, mute_vol);
-               codec->codec_write(codec, AC97_HEADPHONE_VOL, mute_vol);
-               codec->codec_write(codec, AC97_PCMOUT_VOL, mute_vol);
-               
-               /* Power down the DAC */
-               dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
-               codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200);
-               /* Load the rate and read the effective rate */
-               codec->codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate);
-               new_rate=codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE);
-               /* Power it back up */
-               codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
-
-               /* Restore volumes */
-               codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mast_vol);
-               codec->codec_write(codec, AC97_MASTER_VOL_MONO, mono_vol);
-               codec->codec_write(codec, AC97_HEADPHONE_VOL, phone_vol);
-               codec->codec_write(codec, AC97_PCMOUT_VOL, pcm_vol);
-       }
-       return new_rate;
-}
-
-EXPORT_SYMBOL(ac97_set_dac_rate);
-
-/**
- *     ac97_set_adc_rate       -       set codec rate adaption
- *     @codec: ac97 code
- *     @rate: rate in hertz
- *
- *     Set the ADC rate. Assumes the codec supports VRA. The caller is
- *     expected to have checked this little detail.
- */
-
-unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate)
-{
-       unsigned int new_rate = rate;
-       u32 dacp;
-
-       if(rate != codec->codec_read(codec, AC97_PCM_LR_ADC_RATE))
-       {
-               /* Power down the ADC */
-               dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
-               codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0100);
-               /* Load the rate and read the effective rate */
-               codec->codec_write(codec, AC97_PCM_LR_ADC_RATE, rate);
-               new_rate=codec->codec_read(codec, AC97_PCM_LR_ADC_RATE);
-               /* Power it back up */
-               codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
-       }
-       return new_rate;
-}
-
-EXPORT_SYMBOL(ac97_set_adc_rate);
-
-static int swap_headphone(int remove_master)
-{
-       struct list_head *l;
-       struct ac97_codec *c;
-       
-       if (remove_master) {
-               mutex_lock(&codec_mutex);
-               list_for_each(l, &codecs)
-               {
-                       c = list_entry(l, struct ac97_codec, list);
-                       if (supported_mixer(c, SOUND_MIXER_PHONEOUT))
-                               c->supported_mixers &= ~SOUND_MASK_PHONEOUT;
-               }
-               mutex_unlock(&codec_mutex);
-       } else
-               ac97_hw[SOUND_MIXER_PHONEOUT].offset = AC97_MASTER_VOL_STEREO;
-
-       /* Scale values already match */
-       ac97_hw[SOUND_MIXER_VOLUME].offset = AC97_MASTER_VOL_MONO;
-       return 0;
-}
-
-static int apply_quirk(int quirk)
-{
-       switch (quirk) {
-       case AC97_TUNE_NONE:
-               return 0;
-       case AC97_TUNE_HP_ONLY:
-               return swap_headphone(1);
-       case AC97_TUNE_SWAP_HP:
-               return swap_headphone(0);
-       case AC97_TUNE_SWAP_SURROUND:
-               return -ENOSYS; /* not yet implemented */
-       case AC97_TUNE_AD_SHARING:
-               return -ENOSYS; /* not yet implemented */
-       case AC97_TUNE_ALC_JACK:
-               return -ENOSYS; /* not yet implemented */
-       }
-       return -EINVAL;
-}
-
-/**
- *     ac97_tune_hardware - tune up the hardware
- *     @pdev: pci_dev pointer
- *     @quirk: quirk list
- *     @override: explicit quirk value (overrides if not AC97_TUNE_DEFAULT)
- *
- *     Do some workaround for each pci device, such as renaming of the
- *     headphone (true line-out) control as "Master".
- *     The quirk-list must be terminated with a zero-filled entry.
- *
- *     Returns zero if successful, or a negative error code on failure.
- */
-
-int ac97_tune_hardware(struct pci_dev *pdev, struct ac97_quirk *quirk, int override)
-{
-       int result;
-
-       if (!quirk)
-               return -EINVAL;
-
-       if (override != AC97_TUNE_DEFAULT) {
-               result = apply_quirk(override);
-               if (result < 0)
-                       printk(KERN_ERR "applying quirk type %d failed (%d)\n", override, result);
-               return result;
-       }
-
-       for (; quirk->vendor; quirk++) {
-               if (quirk->vendor != pdev->subsystem_vendor)
-                       continue;
-               if ((! quirk->mask && quirk->device == pdev->subsystem_device) ||
-                   quirk->device == (quirk->mask & pdev->subsystem_device)) {
-#ifdef DEBUG
-                       printk("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, pdev->subsystem_device);
-#endif
-                       result = apply_quirk(quirk->type);
-                       if (result < 0)
-                               printk(KERN_ERR "applying quirk type %d for %s failed (%d)\n", quirk->type, quirk->name, result);
-                       return result;
-               }
-       }
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(ac97_tune_hardware);
-
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
deleted file mode 100644 (file)
index 4d5cf05..0000000
+++ /dev/null
@@ -1,1139 +0,0 @@
-/*
-    btaudio - bt878 audio dma driver for linux 2.4.x
-
-    (c) 2000-2002 Gerd Knorr <kraxel@bytesex.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/slab.h>
-#include <linux/kdev_t.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-
-/* mmio access */
-#define btwrite(dat,adr)    writel((dat), (bta->mmio+(adr)))
-#define btread(adr)         readl(bta->mmio+(adr))
-
-#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
-#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
-#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-
-/* registers (shifted because bta->mmio is long) */
-#define REG_INT_STAT      (0x100 >> 2)
-#define REG_INT_MASK      (0x104 >> 2)
-#define REG_GPIO_DMA_CTL  (0x10c >> 2)
-#define REG_PACKET_LEN    (0x110 >> 2)
-#define REG_RISC_STRT_ADD (0x114 >> 2)
-#define REG_RISC_COUNT    (0x120 >> 2)
-
-/* IRQ bits - REG_INT_(STAT|MASK) */
-#define IRQ_SCERR         (1 << 19)
-#define IRQ_OCERR         (1 << 18)
-#define IRQ_PABORT        (1 << 17)
-#define IRQ_RIPERR        (1 << 16)
-#define IRQ_PPERR         (1 << 15)
-#define IRQ_FDSR          (1 << 14)
-#define IRQ_FTRGT         (1 << 13)
-#define IRQ_FBUS          (1 << 12)
-#define IRQ_RISCI         (1 << 11)
-#define IRQ_OFLOW         (1 <<  3)
-
-#define IRQ_BTAUDIO       (IRQ_SCERR | IRQ_OCERR | IRQ_PABORT | IRQ_RIPERR |\
-                          IRQ_PPERR | IRQ_FDSR  | IRQ_FTRGT  | IRQ_FBUS   |\
-                          IRQ_RISCI)
-
-/* REG_GPIO_DMA_CTL bits */
-#define DMA_CTL_A_PWRDN   (1 << 26)
-#define DMA_CTL_DA_SBR    (1 << 14)
-#define DMA_CTL_DA_ES2    (1 << 13)
-#define DMA_CTL_ACAP_EN   (1 <<  4)
-#define DMA_CTL_RISC_EN   (1 <<  1)
-#define DMA_CTL_FIFO_EN   (1 <<  0)
-
-/* RISC instructions */
-#define RISC_WRITE        (0x01 << 28)
-#define RISC_JUMP         (0x07 << 28)
-#define RISC_SYNC         (0x08 << 28)
-
-/* RISC bits */
-#define RISC_WR_SOL       (1 << 27)
-#define RISC_WR_EOL       (1 << 26)
-#define RISC_IRQ          (1 << 24)
-#define RISC_SYNC_RESYNC  (1 << 15)
-#define RISC_SYNC_FM1     0x06
-#define RISC_SYNC_VRO     0x0c
-
-#define HWBASE_AD (448000)
-
-/* -------------------------------------------------------------- */
-
-struct btaudio {
-       /* linked list */
-       struct btaudio *next;
-
-       /* device info */
-       int            dsp_digital;
-       int            dsp_analog;
-       int            mixer_dev;
-       struct pci_dev *pci;
-       unsigned int   irq;
-       unsigned long  mem;
-       unsigned long  __iomem *mmio;
-
-       /* locking */
-       int            users;
-       struct mutex lock;
-
-       /* risc instructions */
-       unsigned int   risc_size;
-       unsigned long  *risc_cpu;
-       dma_addr_t     risc_dma;
-
-       /* audio data */
-       unsigned int   buf_size;
-       unsigned char  *buf_cpu;
-       dma_addr_t     buf_dma;
-
-       /* buffer setup */
-       int line_bytes;
-       int line_count;
-       int block_bytes;
-       int block_count;
-
-       /* read fifo management */
-       int recording;
-       int dma_block;
-       int read_offset;
-       int read_count;
-       wait_queue_head_t readq;
-
-       /* settings */
-       int gain[3];
-       int source;
-       int bits;
-       int decimation;
-       int mixcount;
-       int sampleshift;
-       int channels;
-       int analog;
-       int rate;
-};
-
-struct cardinfo {
-       char *name;
-       int rate;
-};
-
-static struct btaudio *btaudios;
-static unsigned int debug;
-static unsigned int irq_debug;
-
-/* -------------------------------------------------------------- */
-
-#define BUF_DEFAULT 128*1024
-#define BUF_MIN         8192
-
-static int alloc_buffer(struct btaudio *bta)
-{
-       if (NULL == bta->buf_cpu) {
-               for (bta->buf_size = BUF_DEFAULT; bta->buf_size >= BUF_MIN;
-                    bta->buf_size = bta->buf_size >> 1) {
-                       bta->buf_cpu = pci_alloc_consistent
-                               (bta->pci, bta->buf_size, &bta->buf_dma);
-                       if (NULL != bta->buf_cpu)
-                               break;
-               }
-               if (NULL == bta->buf_cpu)
-                       return -ENOMEM;
-               memset(bta->buf_cpu,0,bta->buf_size);
-       }
-       if (NULL == bta->risc_cpu) {
-               bta->risc_size = PAGE_SIZE;
-               bta->risc_cpu = pci_alloc_consistent
-                       (bta->pci, bta->risc_size, &bta->risc_dma);
-               if (NULL == bta->risc_cpu) {
-                       pci_free_consistent(bta->pci, bta->buf_size, bta->buf_cpu, bta->buf_dma);
-                       bta->buf_cpu = NULL;
-                       return -ENOMEM;
-               }
-       }
-       return 0;
-}
-
-static void free_buffer(struct btaudio *bta)
-{
-       if (NULL != bta->buf_cpu) {
-               pci_free_consistent(bta->pci, bta->buf_size,
-                                   bta->buf_cpu, bta->buf_dma);
-               bta->buf_cpu = NULL;
-       }
-       if (NULL != bta->risc_cpu) {
-               pci_free_consistent(bta->pci, bta->risc_size,
-                                   bta->risc_cpu, bta->risc_dma);
-               bta->risc_cpu = NULL;
-       }
-}
-
-static int make_risc(struct btaudio *bta)
-{
-       int rp, bp, line, block;
-       unsigned long risc;
-
-       bta->block_bytes = bta->buf_size >> 4;
-       bta->block_count = 1 << 4;
-       bta->line_bytes  = bta->block_bytes;
-       bta->line_count  = bta->block_count;
-       while (bta->line_bytes > 4095) {
-               bta->line_bytes >>= 1;
-               bta->line_count <<= 1;
-       }
-       if (bta->line_count > 255)
-               return -EINVAL;
-       if (debug)
-               printk(KERN_DEBUG
-                      "btaudio: bufsize=%d - bs=%d bc=%d - ls=%d, lc=%d\n",
-                      bta->buf_size,bta->block_bytes,bta->block_count,
-                      bta->line_bytes,bta->line_count);
-        rp = 0; bp = 0;
-       block = 0;
-       bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_FM1);
-       bta->risc_cpu[rp++] = cpu_to_le32(0);
-       for (line = 0; line < bta->line_count; line++) {
-               risc  = RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL;
-               risc |= bta->line_bytes;
-               if (0 == (bp & (bta->block_bytes-1))) {
-                       risc |= RISC_IRQ;
-                       risc |= (block  & 0x0f) << 16;
-                       risc |= (~block & 0x0f) << 20;
-                       block++;
-               }
-               bta->risc_cpu[rp++] = cpu_to_le32(risc);
-               bta->risc_cpu[rp++] = cpu_to_le32(bta->buf_dma + bp);
-               bp += bta->line_bytes;
-       }
-       bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_VRO);
-       bta->risc_cpu[rp++] = cpu_to_le32(0);
-       bta->risc_cpu[rp++] = cpu_to_le32(RISC_JUMP); 
-       bta->risc_cpu[rp++] = cpu_to_le32(bta->risc_dma);
-       return 0;
-}
-
-static int start_recording(struct btaudio *bta)
-{
-       int ret;
-
-       if (0 != (ret = alloc_buffer(bta)))
-               return ret;
-       if (0 != (ret = make_risc(bta)))
-               return ret;
-
-       btwrite(bta->risc_dma, REG_RISC_STRT_ADD);
-       btwrite((bta->line_count << 16) | bta->line_bytes,
-               REG_PACKET_LEN);
-       btwrite(IRQ_BTAUDIO, REG_INT_MASK);
-       if (bta->analog) {
-               btwrite(DMA_CTL_ACAP_EN |
-                       DMA_CTL_RISC_EN |
-                       DMA_CTL_FIFO_EN |
-                       DMA_CTL_DA_ES2  |
-                       ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |
-                       (bta->gain[bta->source] << 28) |
-                       (bta->source            << 24) |
-                       (bta->decimation        <<  8),
-                       REG_GPIO_DMA_CTL);
-       } else {
-               btwrite(DMA_CTL_ACAP_EN |
-                       DMA_CTL_RISC_EN |
-                       DMA_CTL_FIFO_EN |
-                       DMA_CTL_DA_ES2  |
-                       DMA_CTL_A_PWRDN |
-                       (1 << 6)   |
-                       ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |
-                       (bta->gain[bta->source] << 28) |
-                       (bta->source            << 24) |
-                       (bta->decimation        <<  8),
-                       REG_GPIO_DMA_CTL);
-       }
-       bta->dma_block = 0;
-       bta->read_offset = 0;
-       bta->read_count = 0;
-       bta->recording = 1;
-       if (debug)
-               printk(KERN_DEBUG "btaudio: recording started\n");
-       return 0;
-}
-
-static void stop_recording(struct btaudio *bta)
-{
-        btand(~15, REG_GPIO_DMA_CTL);
-       bta->recording = 0;
-       if (debug)
-               printk(KERN_DEBUG "btaudio: recording stopped\n");
-}
-
-
-/* -------------------------------------------------------------- */
-
-static int btaudio_mixer_open(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct btaudio *bta;
-
-       for (bta = btaudios; bta != NULL; bta = bta->next)
-               if (bta->mixer_dev == minor)
-                       break;
-       if (NULL == bta)
-               return -ENODEV;
-
-       if (debug)
-               printk("btaudio: open mixer [%d]\n",minor);
-       file->private_data = bta;
-       return 0;
-}
-
-static int btaudio_mixer_release(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
-                              unsigned int cmd, unsigned long arg)
-{
-       struct btaudio *bta = file->private_data;
-       int ret,val=0,i=0;
-       void __user *argp = (void __user *)arg;
-
-       if (cmd == SOUND_MIXER_INFO) {
-               mixer_info info;
-               memset(&info,0,sizeof(info));
-                strlcpy(info.id,"bt878",sizeof(info.id));
-                strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
-                info.modify_counter = bta->mixcount;
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
-               return 0;
-       }
-       if (cmd == SOUND_OLD_MIXER_INFO) {
-               _old_mixer_info info;
-               memset(&info,0,sizeof(info));
-                strlcpy(info.id, "bt878", sizeof(info.id));
-                strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
-               return 0;
-       }
-       if (cmd == OSS_GETVERSION)
-               return put_user(SOUND_VERSION, (int __user *)argp);
-
-       /* read */
-       if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-               if (get_user(val, (int __user *)argp))
-                       return -EFAULT;
-
-       switch (cmd) {
-       case MIXER_READ(SOUND_MIXER_CAPS):
-               ret = SOUND_CAP_EXCL_INPUT;
-               break;
-       case MIXER_READ(SOUND_MIXER_STEREODEVS):
-               ret = 0;
-               break;
-       case MIXER_READ(SOUND_MIXER_RECMASK):
-       case MIXER_READ(SOUND_MIXER_DEVMASK):
-               ret = SOUND_MASK_LINE1|SOUND_MASK_LINE2|SOUND_MASK_LINE3;
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_RECSRC):
-               if (val & SOUND_MASK_LINE1 && bta->source != 0)
-                       bta->source = 0;
-               else if (val & SOUND_MASK_LINE2 && bta->source != 1)
-                       bta->source = 1;
-               else if (val & SOUND_MASK_LINE3 && bta->source != 2)
-                       bta->source = 2;
-               btaor((bta->gain[bta->source] << 28) |
-                     (bta->source            << 24),
-                     0x0cffffff, REG_GPIO_DMA_CTL);
-       case MIXER_READ(SOUND_MIXER_RECSRC):
-               switch (bta->source) {
-               case 0:  ret = SOUND_MASK_LINE1; break;
-               case 1:  ret = SOUND_MASK_LINE2; break;
-               case 2:  ret = SOUND_MASK_LINE3; break;
-               default: ret = 0;
-               }
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_LINE1):
-       case MIXER_WRITE(SOUND_MIXER_LINE2):
-       case MIXER_WRITE(SOUND_MIXER_LINE3):
-               if (MIXER_WRITE(SOUND_MIXER_LINE1) == cmd)
-                       i = 0;
-               if (MIXER_WRITE(SOUND_MIXER_LINE2) == cmd)
-                       i = 1;
-               if (MIXER_WRITE(SOUND_MIXER_LINE3) == cmd)
-                       i = 2;
-               bta->gain[i] = (val & 0xff) * 15 / 100;
-               if (bta->gain[i] > 15) bta->gain[i] = 15;
-               if (bta->gain[i] <  0) bta->gain[i] =  0;
-               if (i == bta->source)
-                       btaor((bta->gain[bta->source]<<28),
-                             0x0fffffff, REG_GPIO_DMA_CTL);
-               ret  = bta->gain[i] * 100 / 15;
-               ret |= ret << 8;
-               break;
-
-       case MIXER_READ(SOUND_MIXER_LINE1):
-       case MIXER_READ(SOUND_MIXER_LINE2):
-       case MIXER_READ(SOUND_MIXER_LINE3):
-               if (MIXER_READ(SOUND_MIXER_LINE1) == cmd)
-                       i = 0;
-               if (MIXER_READ(SOUND_MIXER_LINE2) == cmd)
-                       i = 1;
-               if (MIXER_READ(SOUND_MIXER_LINE3) == cmd)
-                       i = 2;
-               ret  = bta->gain[i] * 100 / 15;
-               ret |= ret << 8;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-       if (put_user(ret, (int __user *)argp))
-               return -EFAULT;
-       return 0;
-}
-
-static const struct file_operations btaudio_mixer_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = btaudio_mixer_open,
-       .release        = btaudio_mixer_release,
-       .ioctl          = btaudio_mixer_ioctl,
-};
-
-/* -------------------------------------------------------------- */
-
-static int btaudio_dsp_open(struct inode *inode, struct file *file,
-                           struct btaudio *bta, int analog)
-{
-       mutex_lock(&bta->lock);
-       if (bta->users)
-               goto busy;
-       bta->users++;
-       file->private_data = bta;
-
-       bta->analog = analog;
-       bta->dma_block = 0;
-       bta->read_offset = 0;
-       bta->read_count = 0;
-       bta->sampleshift = 0;
-
-       mutex_unlock(&bta->lock);
-       return 0;
-
- busy:
-       mutex_unlock(&bta->lock);
-       return -EBUSY;
-}
-
-static int btaudio_dsp_open_digital(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct btaudio *bta;
-
-       for (bta = btaudios; bta != NULL; bta = bta->next)
-               if (bta->dsp_digital == minor)
-                       break;
-       if (NULL == bta)
-               return -ENODEV;
-       
-       if (debug)
-               printk("btaudio: open digital dsp [%d]\n",minor);
-       return btaudio_dsp_open(inode,file,bta,0);
-}
-
-static int btaudio_dsp_open_analog(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct btaudio *bta;
-
-       for (bta = btaudios; bta != NULL; bta = bta->next)
-               if (bta->dsp_analog == minor)
-                       break;
-       if (NULL == bta)
-               return -ENODEV;
-
-       if (debug)
-               printk("btaudio: open analog dsp [%d]\n",minor);
-       return btaudio_dsp_open(inode,file,bta,1);
-}
-
-static int btaudio_dsp_release(struct inode *inode, struct file *file)
-{
-       struct btaudio *bta = file->private_data;
-
-       mutex_lock(&bta->lock);
-       if (bta->recording)
-               stop_recording(bta);
-       bta->users--;
-       mutex_unlock(&bta->lock);
-       return 0;
-}
-
-static ssize_t btaudio_dsp_read(struct file *file, char __user *buffer,
-                               size_t swcount, loff_t *ppos)
-{
-       struct btaudio *bta = file->private_data;
-       int hwcount = swcount << bta->sampleshift;
-       int nsrc, ndst, err, ret = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&bta->readq, &wait);
-       mutex_lock(&bta->lock);
-       while (swcount > 0) {
-               if (0 == bta->read_count) {
-                       if (!bta->recording) {
-                               if (0 != (err = start_recording(bta))) {
-                                       if (0 == ret)
-                                               ret = err;
-                                       break;
-                               }
-                       }
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (0 == ret)
-                                       ret = -EAGAIN;
-                               break;
-                       }
-                       mutex_unlock(&bta->lock);
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule();
-                       mutex_lock(&bta->lock);
-                       if(signal_pending(current)) {
-                               if (0 == ret)
-                                       ret = -EINTR;
-                               break;
-                       }
-               }
-               nsrc = (bta->read_count < hwcount) ? bta->read_count : hwcount;
-               if (nsrc > bta->buf_size - bta->read_offset)
-                       nsrc = bta->buf_size - bta->read_offset;
-               ndst = nsrc >> bta->sampleshift;
-               
-               if ((bta->analog  && 0 == bta->sampleshift) ||
-                   (!bta->analog && 2 == bta->channels)) {
-                       /* just copy */
-                       if (copy_to_user(buffer + ret, bta->buf_cpu + bta->read_offset, nsrc)) {
-                               if (0 == ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-
-               } else if (!bta->analog) {
-                       /* stereo => mono (digital audio) */
-                       __s16 *src = (__s16*)(bta->buf_cpu + bta->read_offset);
-                       __s16 __user *dst = (__s16 __user *)(buffer + ret);
-                       __s16 avg;
-                       int n = ndst>>1;
-                       if (!access_ok(VERIFY_WRITE, dst, ndst)) {
-                               if (0 == ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-                       for (; n; n--, dst++) {
-                               avg  = (__s16)le16_to_cpu(*src) / 2; src++;
-                               avg += (__s16)le16_to_cpu(*src) / 2; src++;
-                               __put_user(cpu_to_le16(avg),dst);
-                       }
-
-               } else if (8 == bta->bits) {
-                       /* copy + byte downsampling (audio A/D) */
-                       __u8 *src = bta->buf_cpu + bta->read_offset;
-                       __u8 __user *dst = buffer + ret;
-                       int n = ndst;
-                       if (!access_ok(VERIFY_WRITE, dst, ndst)) {
-                               if (0 == ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-                       for (; n; n--, src += (1 << bta->sampleshift), dst++)
-                               __put_user(*src, dst);
-
-               } else {
-                       /* copy + word downsampling (audio A/D) */
-                       __u16 *src = (__u16*)(bta->buf_cpu + bta->read_offset);
-                       __u16 __user *dst = (__u16 __user *)(buffer + ret);
-                       int n = ndst>>1;
-                       if (!access_ok(VERIFY_WRITE,dst,ndst)) {
-                               if (0 == ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-                       for (; n; n--, src += (1 << bta->sampleshift), dst++)
-                               __put_user(*src, dst);
-               }
-
-               ret     += ndst;
-               swcount -= ndst;
-               hwcount -= nsrc;
-               bta->read_count  -= nsrc;
-               bta->read_offset += nsrc;
-               if (bta->read_offset == bta->buf_size)
-                       bta->read_offset = 0;
-       }
-       mutex_unlock(&bta->lock);
-       remove_wait_queue(&bta->readq, &wait);
-       current->state = TASK_RUNNING;
-       return ret;
-}
-
-static ssize_t btaudio_dsp_write(struct file *file, const char __user *buffer,
-                                size_t count, loff_t *ppos)
-{
-       return -EINVAL;
-}
-
-static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg)
-{
-       struct btaudio *bta = file->private_data;
-       int s, i, ret, val = 0;
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       
-        switch (cmd) {
-        case OSS_GETVERSION:
-                return put_user(SOUND_VERSION, p);
-        case SNDCTL_DSP_GETCAPS:
-               return 0;
-
-        case SNDCTL_DSP_SPEED:
-               if (get_user(val, p))
-                       return -EFAULT;
-               if (bta->analog) {
-                       for (s = 0; s < 16; s++)
-                               if (val << s >= HWBASE_AD*4/15)
-                                       break;
-                       for (i = 15; i >= 5; i--)
-                               if (val << s <= HWBASE_AD*4/i)
-                                       break;
-                       bta->sampleshift = s;
-                       bta->decimation  = i;
-                       if (debug)
-                               printk(KERN_DEBUG "btaudio: rate: req=%d  "
-                                      "dec=%d shift=%d hwrate=%d swrate=%d\n",
-                                      val,i,s,(HWBASE_AD*4/i),(HWBASE_AD*4/i)>>s);
-               } else {
-                       bta->sampleshift = (bta->channels == 2) ? 0 : 1;
-                       bta->decimation  = 0;
-               }
-               if (bta->recording) {
-                       mutex_lock(&bta->lock);
-                       stop_recording(bta);
-                       start_recording(bta);
-                       mutex_unlock(&bta->lock);
-               }
-               /* fall through */
-        case SOUND_PCM_READ_RATE:
-               if (bta->analog) {
-                       return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, p);
-               } else {
-                       return put_user(bta->rate, p);
-               }
-
-        case SNDCTL_DSP_STEREO:
-               if (!bta->analog) {
-                       if (get_user(val, p))
-                               return -EFAULT;
-                       bta->channels    = (val > 0) ? 2 : 1;
-                       bta->sampleshift = (bta->channels == 2) ? 0 : 1;
-                       if (debug)
-                               printk(KERN_INFO
-                                      "btaudio: stereo=%d channels=%d\n",
-                                      val,bta->channels);
-               } else {
-                       if (val == 1)
-                               return -EFAULT;
-                       else {
-                               bta->channels = 1;
-                               if (debug)
-                                       printk(KERN_INFO
-                                              "btaudio: stereo=0 channels=1\n");
-                       }
-               }
-               return put_user((bta->channels)-1, p);
-
-        case SNDCTL_DSP_CHANNELS:
-               if (!bta->analog) {
-                       if (get_user(val, p))
-                               return -EFAULT;
-                       bta->channels    = (val > 1) ? 2 : 1;
-                       bta->sampleshift = (bta->channels == 2) ? 0 : 1;
-                       if (debug)
-                               printk(KERN_DEBUG
-                                      "btaudio: val=%d channels=%d\n",
-                                      val,bta->channels);
-               }
-               /* fall through */
-        case SOUND_PCM_READ_CHANNELS:
-               return put_user(bta->channels, p);
-               
-        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-               if (bta->analog)
-                       return put_user(AFMT_S16_LE|AFMT_S8, p);
-               else
-                       return put_user(AFMT_S16_LE, p);
-
-        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-               if (get_user(val, p))
-                       return -EFAULT;
-                if (val != AFMT_QUERY) {
-                       if (bta->analog)
-                               bta->bits = (val == AFMT_S8) ? 8 : 16;
-                       else
-                               bta->bits = 16;
-                       if (bta->recording) {
-                               mutex_lock(&bta->lock);
-                               stop_recording(bta);
-                               start_recording(bta);
-                               mutex_unlock(&bta->lock);
-                       }
-               }
-               if (debug)
-                       printk(KERN_DEBUG "btaudio: fmt: bits=%d\n",bta->bits);
-                return put_user((bta->bits==16) ? AFMT_S16_LE : AFMT_S8,
-                               p);
-               break;
-        case SOUND_PCM_READ_BITS:
-               return put_user(bta->bits, p);
-
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_RESET:
-               if (bta->recording) {
-                       mutex_lock(&bta->lock);
-                       stop_recording(bta);
-                       mutex_unlock(&bta->lock);
-               }
-               return 0;
-        case SNDCTL_DSP_GETBLKSIZE:
-               if (!bta->recording) {
-                       if (0 != (ret = alloc_buffer(bta)))
-                               return ret;
-                       if (0 != (ret = make_risc(bta)))
-                               return ret;
-               }
-               return put_user(bta->block_bytes>>bta->sampleshift,p);
-
-        case SNDCTL_DSP_SYNC:
-               /* NOP */
-               return 0;
-       case SNDCTL_DSP_GETISPACE:
-       {
-               audio_buf_info info;
-               if (!bta->recording)
-                       return -EINVAL;
-               info.fragsize = bta->block_bytes>>bta->sampleshift;
-               info.fragstotal = bta->block_count;
-               info.bytes = bta->read_count;
-               info.fragments = info.bytes / info.fragsize;
-               if (debug)
-                       printk(KERN_DEBUG "btaudio: SNDCTL_DSP_GETISPACE "
-                              "returns %d/%d/%d/%d\n",
-                              info.fragsize, info.fragstotal,
-                              info.bytes, info.fragments);
-               if (copy_to_user(argp, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-#if 0 /* TODO */
-        case SNDCTL_DSP_GETTRIGGER:
-        case SNDCTL_DSP_SETTRIGGER:
-        case SNDCTL_DSP_SETFRAGMENT:
-#endif
-       default:
-               return -EINVAL;
-       }
-}
-
-static unsigned int btaudio_dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct btaudio *bta = file->private_data;
-       unsigned int mask = 0;
-
-       poll_wait(file, &bta->readq, wait);
-
-       if (0 != bta->read_count)
-               mask |= (POLLIN | POLLRDNORM);
-
-       return mask;
-}
-
-static const struct file_operations btaudio_digital_dsp_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = btaudio_dsp_open_digital,
-       .release        = btaudio_dsp_release,
-       .read           = btaudio_dsp_read,
-       .write          = btaudio_dsp_write,
-       .ioctl          = btaudio_dsp_ioctl,
-       .poll           = btaudio_dsp_poll,
-};
-
-static const struct file_operations btaudio_analog_dsp_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = btaudio_dsp_open_analog,
-       .release        = btaudio_dsp_release,
-       .read           = btaudio_dsp_read,
-       .write          = btaudio_dsp_write,
-       .ioctl          = btaudio_dsp_ioctl,
-       .poll           = btaudio_dsp_poll,
-};
-
-/* -------------------------------------------------------------- */
-
-static char *irq_name[] = { "", "", "", "OFLOW", "", "", "", "", "", "", "",
-                           "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
-                           "RIPERR", "PABORT", "OCERR", "SCERR" };
-
-static irqreturn_t btaudio_irq(int irq, void *dev_id)
-{
-       int count = 0;
-       u32 stat,astat;
-       struct btaudio *bta = dev_id;
-       int handled = 0;
-
-       for (;;) {
-               count++;
-               stat  = btread(REG_INT_STAT);
-               astat = stat & btread(REG_INT_MASK);
-               if (!astat)
-                       return IRQ_RETVAL(handled);
-               handled = 1;
-               btwrite(astat,REG_INT_STAT);
-
-               if (irq_debug) {
-                       int i;
-                       printk(KERN_DEBUG "btaudio: irq loop=%d risc=%x, bits:",
-                              count, stat>>28);
-                       for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
-                               if (stat & (1 << i))
-                                       printk(" %s",irq_name[i]);
-                               if (astat & (1 << i))
-                                       printk("*");
-                       }
-                       printk("\n");
-               }
-               if (stat & IRQ_RISCI) {
-                       int blocks;
-                       blocks = (stat >> 28) - bta->dma_block;
-                       if (blocks < 0)
-                               blocks += bta->block_count;
-                       bta->dma_block = stat >> 28;
-                       if (bta->read_count + 2*bta->block_bytes > bta->buf_size) {
-                               stop_recording(bta);
-                               printk(KERN_INFO "btaudio: buffer overrun\n");
-                       }
-                       if (blocks > 0) {
-                               bta->read_count += blocks * bta->block_bytes;
-                               wake_up_interruptible(&bta->readq);
-                       }
-               }
-               if (count > 10) {
-                       printk(KERN_WARNING
-                              "btaudio: Oops - irq mask cleared\n");
-                       btwrite(0, REG_INT_MASK);
-               }
-       }
-       return IRQ_NONE;
-}
-
-/* -------------------------------------------------------------- */
-
-static unsigned int dsp1 = -1;
-static unsigned int dsp2 = -1;
-static unsigned int mixer = -1;
-static int latency = -1;
-static int digital = 1;
-static int analog = 1;
-static int rate;
-
-#define BTA_OSPREY200 1
-
-static struct cardinfo cards[] = {
-       [0] = {
-               .name   = "default",
-               .rate   = 32000,
-       },
-       [BTA_OSPREY200] = {
-               .name   = "Osprey 200",
-               .rate   = 44100,
-       },
-};
-
-static int __devinit btaudio_probe(struct pci_dev *pci_dev,
-                                  const struct pci_device_id *pci_id)
-{
-       struct btaudio *bta;
-       struct cardinfo *card = &cards[pci_id->driver_data];
-       unsigned char revision,lat;
-       int rc = -EBUSY;
-
-       if (pci_enable_device(pci_dev))
-               return -EIO;
-       if (!request_mem_region(pci_resource_start(pci_dev,0),
-                               pci_resource_len(pci_dev,0),
-                               "btaudio")) {
-               return -EBUSY;
-       }
-
-       bta = kzalloc(sizeof(*bta),GFP_ATOMIC);
-       if (!bta) {
-               rc = -ENOMEM;
-               goto fail0;
-       }
-
-       bta->pci  = pci_dev;
-       bta->irq  = pci_dev->irq;
-       bta->mem  = pci_resource_start(pci_dev,0);
-       bta->mmio = ioremap(pci_resource_start(pci_dev,0),
-                           pci_resource_len(pci_dev,0));
-
-       bta->source     = 1;
-       bta->bits       = 8;
-       bta->channels   = 1;
-       if (bta->analog) {
-               bta->decimation  = 15;
-       } else {
-               bta->decimation  = 0;
-               bta->sampleshift = 1;
-       }
-
-       /* sample rate */
-       bta->rate = card->rate;
-       if (rate)
-               bta->rate = rate;
-       
-       mutex_init(&bta->lock);
-        init_waitqueue_head(&bta->readq);
-
-       if (-1 != latency) {
-               printk(KERN_INFO "btaudio: setting pci latency timer to %d\n",
-                      latency);
-               pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
-       }
-        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
-        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat);
-        printk(KERN_INFO "btaudio: Bt%x (rev %d) at %02x:%02x.%x, ",
-              pci_dev->device,revision,pci_dev->bus->number,
-              PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn));
-        printk("irq: %d, latency: %d, mmio: 0x%lx\n",
-              bta->irq, lat, bta->mem);
-       printk("btaudio: using card config \"%s\"\n", card->name);
-
-       /* init hw */
-        btwrite(0, REG_GPIO_DMA_CTL);
-        btwrite(0, REG_INT_MASK);
-        btwrite(~0U, REG_INT_STAT);
-       pci_set_master(pci_dev);
-
-       if ((rc = request_irq(bta->irq, btaudio_irq, IRQF_SHARED|IRQF_DISABLED,
-                             "btaudio",(void *)bta)) < 0) {
-               printk(KERN_WARNING
-                      "btaudio: can't request irq (rc=%d)\n",rc);
-               goto fail1;
-       }
-
-       /* register devices */
-       if (digital) {
-               rc = bta->dsp_digital =
-                       register_sound_dsp(&btaudio_digital_dsp_fops,dsp1);
-               if (rc < 0) {
-                       printk(KERN_WARNING
-                              "btaudio: can't register digital dsp (rc=%d)\n",rc);
-                       goto fail2;
-               }
-               printk(KERN_INFO "btaudio: registered device dsp%d [digital]\n",
-                      bta->dsp_digital >> 4);
-       }
-       if (analog) {
-               rc = bta->dsp_analog =
-                       register_sound_dsp(&btaudio_analog_dsp_fops,dsp2);
-               if (rc < 0) {
-                       printk(KERN_WARNING
-                              "btaudio: can't register analog dsp (rc=%d)\n",rc);
-                       goto fail3;
-               }
-               printk(KERN_INFO "btaudio: registered device dsp%d [analog]\n",
-                      bta->dsp_analog >> 4);
-               rc = bta->mixer_dev = register_sound_mixer(&btaudio_mixer_fops,mixer);
-               if (rc < 0) {
-                       printk(KERN_WARNING
-                              "btaudio: can't register mixer (rc=%d)\n",rc);
-                       goto fail4;
-               }
-               printk(KERN_INFO "btaudio: registered device mixer%d\n",
-                      bta->mixer_dev >> 4);
-       }
-
-       /* hook into linked list */
-       bta->next = btaudios;
-       btaudios = bta;
-
-       pci_set_drvdata(pci_dev,bta);
-        return 0;
-
- fail4:
-       unregister_sound_dsp(bta->dsp_analog);
- fail3:
-       if (digital)
-               unregister_sound_dsp(bta->dsp_digital);
- fail2:
-        free_irq(bta->irq,bta);        
- fail1:
-       iounmap(bta->mmio);
-       kfree(bta);
- fail0:
-       release_mem_region(pci_resource_start(pci_dev,0),
-                          pci_resource_len(pci_dev,0));
-       return rc;
-}
-
-static void __devexit btaudio_remove(struct pci_dev *pci_dev)
-{
-       struct btaudio *bta = pci_get_drvdata(pci_dev);
-       struct btaudio *walk;
-
-       /* turn off all DMA / IRQs */
-        btand(~15, REG_GPIO_DMA_CTL);
-        btwrite(0, REG_INT_MASK);
-        btwrite(~0U, REG_INT_STAT);
-
-       /* unregister devices */
-       if (digital) {
-               unregister_sound_dsp(bta->dsp_digital);
-       }
-       if (analog) {
-               unregister_sound_dsp(bta->dsp_analog);
-               unregister_sound_mixer(bta->mixer_dev);
-       }
-
-       /* free resources */
-       free_buffer(bta);
-        free_irq(bta->irq,bta);
-       release_mem_region(pci_resource_start(pci_dev,0),
-                          pci_resource_len(pci_dev,0));
-       iounmap(bta->mmio);
-
-       /* remove from linked list */
-       if (bta == btaudios) {
-               btaudios = NULL;
-       } else {
-               for (walk = btaudios; walk->next != bta; walk = walk->next)
-                       ; /* if (NULL == walk->next) BUG(); */
-               walk->next = bta->next;
-       }
-
-       pci_set_drvdata(pci_dev, NULL);
-       kfree(bta);
-       return;
-}
-
-/* -------------------------------------------------------------- */
-
-static struct pci_device_id btaudio_pci_tbl[] = {
-        {
-               .vendor         = PCI_VENDOR_ID_BROOKTREE,
-               .device         = 0x0878,
-               .subvendor      = 0x0070,
-               .subdevice      = 0xff01,
-               .driver_data    = BTA_OSPREY200,
-       },{
-               .vendor         = PCI_VENDOR_ID_BROOKTREE,
-               .device         = 0x0878,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-       },{
-               .vendor         = PCI_VENDOR_ID_BROOKTREE,
-               .device         = 0x0878,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-        },{
-               /* --- end of list --- */
-       }
-};
-
-static struct pci_driver btaudio_pci_driver = {
-        .name          = "btaudio",
-        .id_table      = btaudio_pci_tbl,
-        .probe         = btaudio_probe,
-        .remove                =  __devexit_p(btaudio_remove),
-};
-
-static int btaudio_init_module(void)
-{
-       printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",
-              digital ? "digital" : "",
-              analog && digital ? "+" : "",
-              analog ? "analog" : "");
-       return pci_register_driver(&btaudio_pci_driver);
-}
-
-static void btaudio_cleanup_module(void)
-{
-       pci_unregister_driver(&btaudio_pci_driver);
-       return;
-}
-
-module_init(btaudio_init_module);
-module_exit(btaudio_cleanup_module);
-
-module_param(dsp1, int, S_IRUGO);
-module_param(dsp2, int, S_IRUGO);
-module_param(mixer, int, S_IRUGO);
-module_param(debug, int, S_IRUGO | S_IWUSR);
-module_param(irq_debug, int, S_IRUGO | S_IWUSR);
-module_param(digital, int, S_IRUGO);
-module_param(analog, int, S_IRUGO);
-module_param(rate, int, S_IRUGO);
-module_param(latency, int, S_IRUGO);
-MODULE_PARM_DESC(latency,"pci latency timer");
-
-MODULE_DEVICE_TABLE(pci, btaudio_pci_tbl);
-MODULE_DESCRIPTION("bt878 audio dma driver");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/sound/oss/cs4232.c b/sound/oss/cs4232.c
deleted file mode 100644 (file)
index de40e21..0000000
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- *     cs4232.c
- *
- * The low level driver for Crystal CS4232 based cards. The CS4232 is
- * a PnP compatible chip which contains a CS4231A codec, SB emulation,
- * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM 
- * interfaces. This is just a temporary driver until full PnP support
- * gets implemented. Just the WSS codec, FM synth and the MIDI ports are
- * supported. Other interfaces are left uninitialized.
- *
- * ifdef ...WAVEFRONT...
- * 
- *   Support is provided for initializing the WaveFront synth
- *   interface as well, which is logical device #4. Note that if
- *   you have a Tropez+ card, you probably don't need to setup
- *   the CS4232-supported MIDI interface, since it corresponds to
- *   the internal 26-pin header that's hard to access. Using this
- *   requires an additional IRQ, a resource none too plentiful in
- *   this environment. Just don't set module parameters mpuio and
- *   mpuirq, and the MIDI port will be left uninitialized. You can
- *   still use the ICS2115 hosted MIDI interface which corresponds
- *   to the 9-pin D connector on the back of the card.
- *
- * endif  ...WAVEFRONT...
- *
- * Supported chips are:
- *      CS4232
- *      CS4236
- *      CS4236B
- *
- * Note: You will need a PnP config setup to initialise some CS4232 boards
- * anyway.
- *
- * Changes
- *      John Rood               Added Bose Sound System Support.
- *      Toshio Spoor
- *     Alan Cox                Modularisation, Basic cleanups.
- *      Paul Barton-Davis      Separated MPU configuration, added
- *                                       Tropez+ (WaveFront) support
- *     Christoph Hellwig       Adapted to module_init/module_exit,
- *                                     simple cleanups
- *     Arnaldo C. de Melo      got rid of attach_uart401
- *     Bartlomiej Zolnierkiewicz
- *                             Added some __init/__initdata/__exit
- *     Marcus Meissner         Added ISA PnP support.
- */
-
-#include <linux/pnp.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-#define KEY_PORT       0x279   /* Same as LPT1 status port */
-#define CSN_NUM                0x99    /* Just a random number */
-#define INDEX_ADDRESS   0x00    /* (R0) Index Address Register */
-#define INDEX_DATA      0x01    /* (R1) Indexed Data Register */
-#define PIN_CONTROL     0x0a    /* (I10) Pin Control */
-#define ENABLE_PINS     0xc0    /* XCTRL0/XCTRL1 enable */
-
-static void CS_OUT(unsigned char a)
-{
-       outb(a, KEY_PORT);
-}
-
-#define CS_OUT2(a, b)          {CS_OUT(a);CS_OUT(b);}
-#define CS_OUT3(a, b, c)       {CS_OUT(a);CS_OUT(b);CS_OUT(c);}
-
-static int __initdata bss       = 0;
-static int mpu_base, mpu_irq;
-static int synth_base, synth_irq;
-static int mpu_detected;
-
-static int probe_cs4232_mpu(struct address_info *hw_config)
-{
-       /*
-        *      Just write down the config values.
-        */
-
-       mpu_base = hw_config->io_base;
-       mpu_irq = hw_config->irq;
-
-       return 1;
-}
-
-static unsigned char crystal_key[] =   /* A 32 byte magic key sequence */
-{
-       0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
-       0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,
-       0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13,
-       0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a
-};
-
-static void sleep(unsigned howlong)
-{
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(howlong);
-}
-
-static void enable_xctrl(int baseio)
-{
-        unsigned char regd;
-                
-        /*
-         * Some IBM Aptiva's have the Bose Sound System. By default
-         * the Bose Amplifier is disabled. The amplifier will be 
-         * activated, by setting the XCTRL0 and XCTRL1 bits.
-         * Volume of the monitor bose speakers/woofer, can then
-         * be set by changing the PCM volume.
-         *
-         */
-                
-        printk("cs4232: enabling Bose Sound System Amplifier.\n");
-        
-        /* Switch to Pin Control Address */                   
-        regd = inb(baseio + INDEX_ADDRESS) & 0xe0;
-        outb(((unsigned char) (PIN_CONTROL | regd)), baseio + INDEX_ADDRESS );
-        
-        /* Activate the XCTRL0 and XCTRL1 Pins */
-        regd = inb(baseio + INDEX_DATA);
-        outb(((unsigned char) (ENABLE_PINS | regd)), baseio + INDEX_DATA );
-}
-
-static int __init probe_cs4232(struct address_info *hw_config, int isapnp_configured)
-{
-       int i, n;
-       int base = hw_config->io_base, irq = hw_config->irq;
-       int dma1 = hw_config->dma, dma2 = hw_config->dma2;
-       struct resource *ports;
-
-       if (base == -1 || irq == -1 || dma1 == -1) {
-               printk(KERN_ERR "cs4232: dma, irq and io must be set.\n");
-               return 0;
-       }
-
-       /*
-        * Verify that the I/O port range is free.
-        */
-
-       ports = request_region(base, 4, "ad1848");
-       if (!ports) {
-               printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base);
-               return 0;
-       }
-       if (ad1848_detect(ports, NULL, hw_config->osp)) {
-               goto got_it;    /* The card is already active */
-       }
-       if (isapnp_configured) {
-               printk(KERN_ERR "cs4232.c: ISA PnP configured, but not detected?\n");
-               goto fail;
-       }
-
-       /*
-        * This version of the driver doesn't use the PnP method when configuring
-        * the card but a simplified method defined by Crystal. This means that
-        * just one CS4232 compatible device can exist on the system. Also this
-        * method conflicts with possible PnP support in the OS. For this reason 
-        * driver is just a temporary kludge.
-        *
-        * Also the Cirrus/Crystal method doesn't always work. Try ISA PnP first ;)
-        */
-
-       /*
-        * Repeat initialization few times since it doesn't always succeed in
-        * first time.
-        */
-
-       for (n = 0; n < 4; n++)
-       {       
-               /*
-                *      Wake up the card by sending a 32 byte Crystal key to the key port.
-                */
-               
-               for (i = 0; i < 32; i++)
-                       CS_OUT(crystal_key[i]);
-
-               sleep(HZ / 10);
-
-               /*
-                *      Now set the CSN (Card Select Number).
-                */
-
-               CS_OUT2(0x06, CSN_NUM);
-
-               /*
-                *      Then set some config bytes. First logical device 0 
-                */
-
-               CS_OUT2(0x15, 0x00);    /* Select logical device 0 (WSS/SB/FM) */
-               CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */
-
-               if (!request_region(0x388, 4, "FM"))    /* Not free */
-                       CS_OUT3(0x48, 0x00, 0x00)       /* FM base off */
-               else {
-                       release_region(0x388, 4);
-                       CS_OUT3(0x48, 0x03, 0x88);      /* FM base 0x388 */
-               }
-
-               CS_OUT3(0x42, 0x00, 0x00);      /* SB base off */
-               CS_OUT2(0x22, irq);             /* SB+WSS IRQ */
-               CS_OUT2(0x2a, dma1);            /* SB+WSS DMA */
-
-               if (dma2 != -1)
-                       CS_OUT2(0x25, dma2)     /* WSS DMA2 */
-               else
-                       CS_OUT2(0x25, 4);       /* No WSS DMA2 */
-
-               CS_OUT2(0x33, 0x01);    /* Activate logical dev 0 */
-
-               sleep(HZ / 10);
-
-               /*
-                * Initialize logical device 3 (MPU)
-                */
-
-               if (mpu_base != 0 && mpu_irq != 0)
-               {
-                       CS_OUT2(0x15, 0x03);    /* Select logical device 3 (MPU) */
-                       CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */
-                       CS_OUT2(0x22, mpu_irq); /* MPU IRQ */
-                       CS_OUT2(0x33, 0x01);    /* Activate logical dev 3 */
-               }
-
-               if(synth_base != 0)
-               {
-                   CS_OUT2 (0x15, 0x04);               /* logical device 4 (WaveFront) */
-                   CS_OUT3 (0x47, (synth_base >> 8) & 0xff,
-                            synth_base & 0xff);        /* base */
-                   CS_OUT2 (0x22, synth_irq);          /* IRQ */
-                   CS_OUT2 (0x33, 0x01);               /* Activate logical dev 4 */
-               }
-
-               /*
-                * Finally activate the chip
-                */
-               
-               CS_OUT(0x79);
-
-               sleep(HZ / 5);
-
-               /*
-                * Then try to detect the codec part of the chip
-                */
-
-               if (ad1848_detect(ports, NULL, hw_config->osp))
-                       goto got_it;
-               
-               sleep(HZ);
-       }
-fail:
-       release_region(base, 4);
-       return 0;
-
-got_it:
-       if (dma2 == -1)
-               dma2 = dma1;
-
-       hw_config->slots[0] = ad1848_init("Crystal audio controller", ports,
-                                         irq,
-                                         dma1,         /* Playback DMA */
-                                         dma2,         /* Capture DMA */
-                                         0,
-                                         hw_config->osp,
-                                         THIS_MODULE);
-
-       if (hw_config->slots[0] != -1 &&
-               audio_devs[hw_config->slots[0]]->mixer_dev!=-1)
-       {       
-               /* Assume the mixer map is as suggested in the CS4232 databook */
-               AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
-               AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
-               AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH);           /* FM synth */
-       }
-       if (mpu_base != 0 && mpu_irq != 0)
-       {
-               static struct address_info hw_config2 = {
-                       0
-               };              /* Ensure it's initialized */
-
-               hw_config2.io_base = mpu_base;
-               hw_config2.irq = mpu_irq;
-               hw_config2.dma = -1;
-               hw_config2.dma2 = -1;
-               hw_config2.always_detect = 0;
-               hw_config2.name = NULL;
-               hw_config2.driver_use_1 = 0;
-               hw_config2.driver_use_2 = 0;
-               hw_config2.card_subtype = 0;
-
-               if (probe_uart401(&hw_config2, THIS_MODULE))
-               {
-                       mpu_detected = 1;
-               }
-               else
-               {
-                       mpu_base = mpu_irq = 0;
-               }
-               hw_config->slots[1] = hw_config2.slots[1];
-       }
-       
-       if (bss)
-               enable_xctrl(base);
-
-       return 1;
-}
-
-static void __devexit unload_cs4232(struct address_info *hw_config)
-{
-       int base = hw_config->io_base, irq = hw_config->irq;
-       int dma1 = hw_config->dma, dma2 = hw_config->dma2;
-
-       if (dma2 == -1)
-               dma2 = dma1;
-
-       ad1848_unload(base,
-                     irq,
-                     dma1,     /* Playback DMA */
-                     dma2,     /* Capture DMA */
-                     0);
-
-       sound_unload_audiodev(hw_config->slots[0]);
-       if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)
-       {
-               static struct address_info hw_config2 =
-               {
-                       0
-               };              /* Ensure it's initialized */
-
-               hw_config2.io_base = mpu_base;
-               hw_config2.irq = mpu_irq;
-               hw_config2.dma = -1;
-               hw_config2.dma2 = -1;
-               hw_config2.always_detect = 0;
-               hw_config2.name = NULL;
-               hw_config2.driver_use_1 = 0;
-               hw_config2.driver_use_2 = 0;
-               hw_config2.card_subtype = 0;
-               hw_config2.slots[1] = hw_config->slots[1];
-
-               unload_uart401(&hw_config2);
-       }
-}
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int __initdata io       = -1;
-static int __initdata irq      = -1;
-static int __initdata dma      = -1;
-static int __initdata dma2     = -1;
-static int __initdata mpuio    = -1;
-static int __initdata mpuirq   = -1;
-static int __initdata synthio  = -1;
-static int __initdata synthirq = -1;
-static int __initdata isapnp   = 1;
-
-static unsigned int cs4232_devices;
-
-MODULE_DESCRIPTION("CS4232 based soundcard driver"); 
-MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis"); 
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io,"base I/O port for AD1848");
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq,"IRQ for AD1848 chip");
-module_param(dma, int, 0);
-MODULE_PARM_DESC(dma,"8 bit DMA for AD1848 chip");
-module_param(dma2, int, 0);
-MODULE_PARM_DESC(dma2,"16 bit DMA for AD1848 chip");
-module_param(mpuio, int, 0);
-MODULE_PARM_DESC(mpuio,"MPU 401 base address");
-module_param(mpuirq, int, 0);
-MODULE_PARM_DESC(mpuirq,"MPU 401 IRQ");
-module_param(synthio, int, 0);
-MODULE_PARM_DESC(synthio,"Maui WaveTable base I/O port");
-module_param(synthirq, int, 0);
-MODULE_PARM_DESC(synthirq,"Maui WaveTable IRQ");
-module_param(isapnp, bool, 0);
-MODULE_PARM_DESC(isapnp,"Enable ISAPnP probing (default 1)");
-module_param(bss, bool, 0);
-MODULE_PARM_DESC(bss,"Enable Bose Sound System Support (default 0)");
-
-/*
- *     Install a CS4232 based card. Need to have ad1848 and mpu401
- *     loaded ready.
- */
-
-/* All cs4232 based cards have the main ad1848 card either as CSC0000 or
- * CSC0100. */
-static const struct pnp_device_id cs4232_pnp_table[] = {
-       { .id = "CSC0100", .driver_data = 0 },
-       { .id = "CSC0000", .driver_data = 0 },
-       /* Guillemot Turtlebeach something appears to be cs4232 compatible
-        * (untested) */
-       { .id = "GIM0100", .driver_data = 0 },
-       { .id = ""}
-};
-
-MODULE_DEVICE_TABLE(pnp, cs4232_pnp_table);
-
-static int __init cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
-       struct address_info *isapnpcfg;
-
-       isapnpcfg = kmalloc(sizeof(*isapnpcfg),GFP_KERNEL);
-       if (!isapnpcfg)
-               return -ENOMEM;
-
-       isapnpcfg->irq          = pnp_irq(dev, 0);
-       isapnpcfg->dma          = pnp_dma(dev, 0);
-       isapnpcfg->dma2         = pnp_dma(dev, 1);
-       isapnpcfg->io_base      = pnp_port_start(dev, 0);
-       if (probe_cs4232(isapnpcfg,TRUE) == 0) {
-               printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n");
-               kfree(isapnpcfg);
-               return -ENODEV;
-       }
-       pnp_set_drvdata(dev,isapnpcfg);
-       cs4232_devices++;
-       return 0;
-}
-
-static void __devexit cs4232_pnp_remove(struct pnp_dev *dev)
-{
-       struct address_info *cfg = pnp_get_drvdata(dev);
-       if (cfg) {
-               unload_cs4232(cfg);
-               kfree(cfg);
-       }
-}
-
-static struct pnp_driver cs4232_driver = {
-       .name           = "cs4232",
-       .id_table       = cs4232_pnp_table,
-       .probe          = cs4232_pnp_probe,
-       .remove         = __devexit_p(cs4232_pnp_remove),
-};
-
-static int __init init_cs4232(void)
-{
-#ifdef CONFIG_SOUND_WAVEFRONT_MODULE
-       if(synthio == -1)
-               printk(KERN_INFO "cs4232: set synthio and synthirq to use the wavefront facilities.\n");
-       else {
-               synth_base = synthio;
-               synth_irq =  synthirq;
-       }
-#else
-       if(synthio != -1)
-               printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n");
-#endif
-       cfg.irq = -1;
-
-       if (isapnp) {
-               pnp_register_driver(&cs4232_driver);
-               if (cs4232_devices)
-                       return 0;
-       }
-
-       if(io==-1||irq==-1||dma==-1)
-       {
-               printk(KERN_ERR "cs4232: Must set io, irq and dma.\n");
-               return -ENODEV;
-       }
-
-       cfg.io_base = io;
-       cfg.irq = irq;
-       cfg.dma = dma;
-       cfg.dma2 = dma2;
-
-       cfg_mpu.io_base = -1;
-       cfg_mpu.irq = -1;
-
-       if (mpuio != -1 && mpuirq != -1) {
-               cfg_mpu.io_base = mpuio;
-               cfg_mpu.irq = mpuirq;
-               probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */
-       }
-
-       if (probe_cs4232(&cfg,FALSE) == 0)
-               return -ENODEV;
-
-       return 0;
-}
-
-static void __exit cleanup_cs4232(void)
-{
-       pnp_unregister_driver(&cs4232_driver);
-        if (cfg.irq != -1)
-               unload_cs4232(&cfg); /* Unloads global MPU as well, if needed */
-}
-
-module_init(init_cs4232);
-module_exit(cleanup_cs4232);
-
-#ifndef MODULE
-static int __init setup_cs4232(char *str)
-{
-       /* io, irq, dma, dma2 mpuio, mpuirq*/
-       int ints[7];
-
-       /* If we have isapnp cards, no need for options */
-       pnp_register_driver(&cs4232_driver);
-       if (cs4232_devices)
-               return 1;
-       
-       str = get_options(str, ARRAY_SIZE(ints), ints);
-       
-       io      = ints[1];
-       irq     = ints[2];
-       dma     = ints[3];
-       dma2    = ints[4];
-       mpuio   = ints[5];
-       mpuirq  = ints[6];
-
-       return 1;
-}
-
-__setup("cs4232=", setup_cs4232);
-#endif
index 71b313479f8331c8ce8e0b0c3e91f19a7699bdaf..3eb782720e58e3a00ffbabb11fb63bfbd38bf5ae 100644 (file)
@@ -14,7 +14,7 @@ config DMASOUND_ATARI
 
 config DMASOUND_PAULA
        tristate "Amiga DMA sound support"
-       depends on (AMIGA || APUS) && SOUND
+       depends on AMIGA && SOUND
        select DMASOUND
        help
          If you want to use the internal audio of your Amiga in Linux, answer
index 90fc058e1159a60b7bd6c52917a061a24d1e9c49..202e8103dc4da39bffe0d740ae56bef1de2a2ceb 100644 (file)
@@ -91,10 +91,6 @@ static irqreturn_t AmiInterrupt(int irq, void *dummy);
      *  power LED are controlled by the same line.
      */
 
-#ifdef CONFIG_APUS
-#define mach_heartbeat ppc_md.heartbeat
-#endif
-
 static void (*saved_heartbeat)(int) = NULL;
 
 static inline void disable_heartbeat(void)
diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
deleted file mode 100644 (file)
index f5e31f1..0000000
+++ /dev/null
@@ -1,3656 +0,0 @@
-/*
- *     Intel i810 and friends ICH driver for Linux
- *     Alan Cox <alan@redhat.com>
- *
- *  Built from:
- *     Low level code:  Zach Brown (original nonworking i810 OSS driver)
- *                      Jaroslav Kysela <perex@suse.cz> (working ALSA driver)
- *
- *     Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
- *     Extended by: Zach Brown <zab@redhat.com>  
- *                     and others..
- *
- *  Hardware Provided By:
- *     Analog Devices (A major AC97 codec maker)
- *     Intel Corp  (you've probably heard of them already)
- *
- *  AC97 clues and assistance provided by
- *     Analog Devices
- *     Zach 'Fufu' Brown
- *     Jeff Garzik
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *     Intel 810 theory of operation
- *
- *     The chipset provides three DMA channels that talk to an AC97
- *     CODEC (AC97 is a digital/analog mixer standard). At its simplest
- *     you get 48Khz audio with basic volume and mixer controls. At the
- *     best you get rate adaption in the codec. We set the card up so
- *     that we never take completion interrupts but instead keep the card
- *     chasing its tail around a ring buffer. This is needed for mmap
- *     mode audio and happens to work rather well for non-mmap modes too.
- *
- *     The board has one output channel for PCM audio (supported) and
- *     a stereo line in and mono microphone input. Again these are normally
- *     locked to 48Khz only. Right now recording is not finished.
- *
- *     There is no midi support, no synth support. Use timidity. To get
- *     esd working you need to use esd -r 48000 as it won't probe 48KHz
- *     by default. mpg123 can't handle 48Khz only audio so use xmms.
- *
- *     Fix The Sound On Dell
- *
- *     Not everyone uses 48KHz. We know of no way to detect this reliably
- *     and certainly not to get the right data. If your i810 audio sounds
- *     stupid you may need to investigate other speeds. According to Analog
- *     they tend to use a 14.318MHz clock which gives you a base rate of
- *     41194Hz.
- *
- *     This is available via the 'ftsodell=1' option. 
- *
- *     If you need to force a specific rate set the clocking= option
- *
- *     This driver is cursed. (Ben LaHaise)
- *
- *  ICH 3 caveats
- *     Intel errata #7 for ICH3 IO. We need to disable SMI stuff
- *     when codec probing. [Not Yet Done]
- *
- *  ICH 4 caveats
- *
- *     The ICH4 has the feature, that the codec ID doesn't have to be 
- *     congruent with the IO connection.
- * 
- *     Therefore, from driver version 0.23 on, there is a "codec ID" <->
- *     "IO register base offset" mapping (card->ac97_id_map) field.
- *   
- *     Juergen "George" Sawinski (jsaw) 
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-#define DRIVER_VERSION "1.01"
-
-#define MODULOP2(a, b) ((a) & ((b) - 1))
-#define MASKP2(a, b) ((a) & ~((b) - 1))
-
-static int ftsodell;
-static int strict_clocking;
-static unsigned int clocking;
-static int spdif_locked;
-static int ac97_quirk = AC97_TUNE_DEFAULT;
-
-//#define DEBUG
-//#define DEBUG2
-//#define DEBUG_INTERRUPTS
-//#define DEBUG_MMAP
-//#define DEBUG_MMIO
-
-#define ADC_RUNNING    1
-#define DAC_RUNNING    2
-
-#define I810_FMT_16BIT 1
-#define I810_FMT_STEREO        2
-#define I810_FMT_MASK  3
-
-#define SPDIF_ON       0x0004
-#define SURR_ON                0x0010
-#define CENTER_LFE_ON  0x0020
-#define VOL_MUTED      0x8000
-
-/* the 810's array of pointers to data buffers */
-
-struct sg_item {
-#define BUSADDR_MASK   0xFFFFFFFE
-       u32 busaddr;    
-#define CON_IOC        0x80000000 /* interrupt on completion */
-#define CON_BUFPAD     0x40000000 /* pad underrun with last sample, else 0 */
-#define CON_BUFLEN_MASK        0x0000ffff /* buffer length in samples */
-       u32 control;
-};
-
-/* an instance of the i810 channel */
-#define SG_LEN 32
-struct i810_channel 
-{
-       /* these sg guys should probably be allocated
-          separately as nocache. Must be 8 byte aligned */
-       struct sg_item sg[SG_LEN];      /* 32*8 */
-       u32 offset;                     /* 4 */
-       u32 port;                       /* 4 */
-       u32 used;
-       u32 num;
-};
-
-/*
- * we have 3 separate dma engines.  pcm in, pcm out, and mic.
- * each dma engine has controlling registers.  These goofy
- * names are from the datasheet, but make it easy to write
- * code while leafing through it.
- *
- * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2, 
- * mic in 2, s/pdif.   Of special interest is the fact that
- * the upper 3 DMA engines on the ICH4 *must* be accessed
- * via mmio access instead of pio access.
- */
-
-#define ENUM_ENGINE(PRE,DIG)                                                                   \
-enum {                                                                                         \
-       PRE##_BASE =    0x##DIG##0,             /* Base Address */                              \
-       PRE##_BDBAR =   0x##DIG##0,             /* Buffer Descriptor list Base Address */       \
-       PRE##_CIV =     0x##DIG##4,             /* Current Index Value */                       \
-       PRE##_LVI =     0x##DIG##5,             /* Last Valid Index */                          \
-       PRE##_SR =      0x##DIG##6,             /* Status Register */                           \
-       PRE##_PICB =    0x##DIG##8,             /* Position In Current Buffer */                \
-       PRE##_PIV =     0x##DIG##a,             /* Prefetched Index Value */                    \
-       PRE##_CR =      0x##DIG##b              /* Control Register */                          \
-}
-
-ENUM_ENGINE(OFF,0);    /* Offsets */
-ENUM_ENGINE(PI,0);     /* PCM In */
-ENUM_ENGINE(PO,1);     /* PCM Out */
-ENUM_ENGINE(MC,2);     /* Mic In */
-
-enum {
-       GLOB_CNT =      0x2c,                   /* Global Control */
-       GLOB_STA =      0x30,                   /* Global Status */
-       CAS      =      0x34                    /* Codec Write Semaphore Register */
-};
-
-ENUM_ENGINE(MC2,4);     /* Mic In 2 */
-ENUM_ENGINE(PI2,5);     /* PCM In 2 */
-ENUM_ENGINE(SP,6);      /* S/PDIF */
-
-enum {
-       SDM =           0x80                    /* SDATA_IN Map Register */
-};
-
-/* interrupts for a dma engine */
-#define DMA_INT_FIFO           (1<<4)  /* fifo under/over flow */
-#define DMA_INT_COMPLETE       (1<<3)  /* buffer read/write complete and ioc set */
-#define DMA_INT_LVI            (1<<2)  /* last valid done */
-#define DMA_INT_CELV           (1<<1)  /* last valid is current */
-#define DMA_INT_DCH            (1)     /* DMA Controller Halted (happens on LVI interrupts) */
-#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
-
-/* interrupts for the whole chip */
-#define INT_SEC                (1<<11)
-#define INT_PRI                (1<<10)
-#define INT_MC         (1<<7)
-#define INT_PO         (1<<6)
-#define INT_PI         (1<<5)
-#define INT_MO         (1<<2)
-#define INT_NI         (1<<1)
-#define INT_GPI                (1<<0)
-#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
-
-/* magic numbers to protect our data structures */
-#define I810_CARD_MAGIC                0x5072696E /* "Prin" */
-#define I810_STATE_MAGIC       0x63657373 /* "cess" */
-#define I810_DMA_MASK          0xffffffff /* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH               3
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97                 4
-
-/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
-/* stream at a minimum for this card to be happy */
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
-/* values are one less than might be expected */
-static const unsigned sample_shift[] = { -1, 0, 0, 1 };
-
-enum {
-       ICH82801AA = 0,
-       ICH82901AB,
-       INTEL440MX,
-       INTELICH2,
-       INTELICH3,
-       INTELICH4,
-       INTELICH5,
-       SI7012,
-       NVIDIA_NFORCE,
-       AMD768,
-       AMD8111
-};
-
-static char * card_names[] = {
-       "Intel ICH 82801AA",
-       "Intel ICH 82901AB",
-       "Intel 440MX",
-       "Intel ICH2",
-       "Intel ICH3",
-       "Intel ICH4",
-       "Intel ICH5",
-       "SiS 7012",
-       "NVIDIA nForce Audio",
-       "AMD 768",
-       "AMD-8111 IOHub"
-};
-
-/* These are capabilities (and bugs) the chipsets _can_ have */
-static struct {
-       int16_t      nr_ac97;
-#define CAP_MMIO                 0x0001
-#define CAP_20BIT_AUDIO_SUPPORT  0x0002
-       u_int16_t flags;
-} card_cap[] = {
-       {  1, 0x0000 }, /* ICH82801AA */
-       {  1, 0x0000 }, /* ICH82901AB */
-       {  1, 0x0000 }, /* INTEL440MX */
-       {  1, 0x0000 }, /* INTELICH2 */
-       {  2, 0x0000 }, /* INTELICH3 */
-       {  3, 0x0003 }, /* INTELICH4 */
-       {  3, 0x0003 }, /* INTELICH5 */
-       /*@FIXME to be verified*/       {  2, 0x0000 }, /* SI7012 */
-       /*@FIXME to be verified*/       {  2, 0x0000 }, /* NVIDIA_NFORCE */
-       /*@FIXME to be verified*/       {  2, 0x0000 }, /* AMD768 */
-       /*@FIXME to be verified*/       {  3, 0x0001 }, /* AMD8111 */
-};
-
-static struct pci_device_id i810_pci_tbl [] = {
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82901AB},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_440MX,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_4,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH5},
-       {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012},
-       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
-       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
-       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
-       {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7445,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768},
-       {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_18,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
-       {PCI_VENDOR_ID_NVIDIA,  PCI_DEVICE_ID_NVIDIA_CK804_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
-       {0,}
-};
-
-MODULE_DEVICE_TABLE (pci, i810_pci_tbl);
-
-#ifdef CONFIG_PM
-#define PM_SUSPENDED(card) (card->pm_suspended)
-#else
-#define PM_SUSPENDED(card) (0)
-#endif
-
-/* "software" or virtual channel, an instance of opened /dev/dsp */
-struct i810_state {
-       unsigned int magic;
-       struct i810_card *card; /* Card info */
-
-       /* single open lock mechanism, only used for recording */
-       struct mutex open_mutex;
-       wait_queue_head_t open_wait;
-
-       /* file mode */
-       mode_t open_mode;
-
-       /* virtual channel number */
-       int virt;
-
-#ifdef CONFIG_PM
-       unsigned int pm_saved_dac_rate,pm_saved_adc_rate;
-#endif
-       struct dmabuf {
-               /* wave sample stuff */
-               unsigned int rate;
-               unsigned char fmt, enable, trigger;
-
-               /* hardware channel */
-               struct i810_channel *read_channel;
-               struct i810_channel *write_channel;
-
-               /* OSS buffer management stuff */
-               void *rawbuf;
-               dma_addr_t dma_handle;
-               unsigned buforder;
-               unsigned numfrag;
-               unsigned fragshift;
-
-               /* our buffer acts like a circular ring */
-               unsigned hwptr;         /* where dma last started, updated by update_ptr */
-               unsigned swptr;         /* where driver last clear/filled, updated by read/write */
-               int count;              /* bytes to be consumed or been generated by dma machine */
-               unsigned total_bytes;   /* total bytes dmaed by hardware */
-
-               unsigned error;         /* number of over/underruns */
-               wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
-
-               /* redundant, but makes calculations easier */
-               /* what the hardware uses */
-               unsigned dmasize;
-               unsigned fragsize;
-               unsigned fragsamples;
-
-               /* what we tell the user to expect */
-               unsigned userfrags;
-               unsigned userfragsize;
-
-               /* OSS stuff */
-               unsigned mapped:1;
-               unsigned ready:1;
-               unsigned update_flag;
-               unsigned ossfragsize;
-               unsigned ossmaxfrags;
-               unsigned subdivision;
-       } dmabuf;
-};
-
-
-struct i810_card {
-       unsigned int magic;
-
-       /* We keep i810 cards in a linked list */
-       struct i810_card *next;
-
-       /* The i810 has a certain amount of cross channel interaction
-          so we use a single per card lock */
-       spinlock_t lock;
-       
-       /* Control AC97 access serialization */
-       spinlock_t ac97_lock;
-
-       /* PCI device stuff */
-       struct pci_dev * pci_dev;
-       u16 pci_id;
-       u16 pci_id_internal; /* used to access card_cap[] */
-#ifdef CONFIG_PM       
-       u16 pm_suspended;
-       int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
-#endif
-       /* soundcore stuff */
-       int dev_audio;
-
-       /* structures for abstraction of hardware facilities, codecs, banks and channels*/
-       u16    ac97_id_map[NR_AC97];
-       struct ac97_codec *ac97_codec[NR_AC97];
-       struct i810_state *states[NR_HW_CH];
-       struct i810_channel *channel;   /* 1:1 to states[] but diff. lifetime */
-       dma_addr_t chandma;
-
-       u16 ac97_features;
-       u16 ac97_status;
-       u16 channels;
-       
-       /* hardware resources */
-       unsigned long ac97base;
-       unsigned long iobase;
-       u32 irq;
-
-       unsigned long ac97base_mmio_phys;
-       unsigned long iobase_mmio_phys;
-       u_int8_t __iomem *ac97base_mmio;
-       u_int8_t __iomem *iobase_mmio;
-
-       int           use_mmio;
-       
-       /* Function support */
-       struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
-       struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);
-       struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *);
-       void (*free_pcm_channel)(struct i810_card *, int chan);
-
-       /* We have a *very* long init time possibly, so use this to block */
-       /* attempts to open our devices before we are ready (stops oops'es) */
-       int initializing;
-};
-
-/* extract register offset from codec struct */
-#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
-
-#define I810_IOREAD(size, type, card, off)                             \
-({                                                                     \
-       type val;                                                       \
-       if (card->use_mmio)                                             \
-               val=read##size(card->iobase_mmio+off);                  \
-       else                                                            \
-               val=in##size(card->iobase+off);                         \
-       val;                                                            \
-})
-
-#define I810_IOREADL(card, off)                I810_IOREAD(l, u32, card, off)
-#define I810_IOREADW(card, off)                I810_IOREAD(w, u16, card, off)
-#define I810_IOREADB(card, off)                I810_IOREAD(b, u8,  card, off)
-
-#define I810_IOWRITE(size, val, card, off)                             \
-({                                                                     \
-       if (card->use_mmio)                                             \
-               write##size(val, card->iobase_mmio+off);                \
-       else                                                            \
-               out##size(val, card->iobase+off);                       \
-})
-
-#define I810_IOWRITEL(val, card, off)  I810_IOWRITE(l, val, card, off)
-#define I810_IOWRITEW(val, card, off)  I810_IOWRITE(w, val, card, off)
-#define I810_IOWRITEB(val, card, off)  I810_IOWRITE(b, val, card, off)
-
-#define GET_CIV(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_CIV), SG_LEN)
-#define GET_LVI(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_LVI), SG_LEN)
-
-/* set LVI from CIV */
-#define CIV_TO_LVI(card, port, off) \
-       I810_IOWRITEB(MODULOP2(GET_CIV((card), (port)) + (off), SG_LEN), (card), (port) + OFF_LVI)
-
-static struct ac97_quirk ac97_quirks[] __devinitdata = {
-       {
-               .vendor = 0x0e11,
-               .device = 0x00b8,
-               .name = "Compaq Evo D510C",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1028,
-               .device = 0x00d8,
-               .name = "Dell Precision 530",   /* AD1885 */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1028,
-               .device = 0x0126,
-               .name = "Dell Optiplex GX260",  /* AD1981A */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1028,
-               .device = 0x012d,
-               .name = "Dell Precision 450",   /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {       /* FIXME: which codec? */
-               .vendor = 0x103c,
-               .device = 0x00c3,
-               .name = "Hewlett-Packard onboard",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x103c,
-               .device = 0x12f1,
-               .name = "HP xw8200",    /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x103c,
-               .device = 0x3008,
-               .name = "HP xw4200",    /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x10f1,
-               .device = 0x2665,
-               .name = "Fujitsu-Siemens Celsius",      /* AD1981? */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x10f1,
-               .device = 0x2885,
-               .name = "AMD64 Mobo",   /* ALC650 */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x110a,
-               .device = 0x0056,
-               .name = "Fujitsu-Siemens Scenic",       /* AD1981? */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x11d4,
-               .device = 0x5375,
-               .name = "ADI AD1985 (discrete)",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1462,
-               .device = 0x5470,
-               .name = "MSI P4 ATX 645 Ultra",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1734,
-               .device = 0x0088,
-               .name = "Fujitsu-Siemens D1522",        /* AD1981 */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .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
-       },
-       {
-               .vendor = 0x8086,
-               .device = 0x4d56,
-               .name = "Intel ICH/AD1885",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1028,
-               .device = 0x012d,
-               .name = "Dell Precision 450",   /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x103c,
-               .device = 0x3008,
-               .name = "HP xw4200",    /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x103c,
-               .device = 0x12f1,
-               .name = "HP xw8200",    /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       { } /* terminator */
-};
-
-static struct i810_card *devs = NULL;
-
-static int i810_open_mixdev(struct inode *inode, struct file *file);
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg);
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
-static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data);
-static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data);
-
-static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card)
-{
-       if(card->channel[1].used==1)
-               return NULL;
-       card->channel[1].used=1;
-       return &card->channel[1];
-}
-
-static struct i810_channel *i810_alloc_rec_pcm_channel(struct i810_card *card)
-{
-       if(card->channel[0].used==1)
-               return NULL;
-       card->channel[0].used=1;
-       return &card->channel[0];
-}
-
-static struct i810_channel *i810_alloc_rec_mic_channel(struct i810_card *card)
-{
-       if(card->channel[2].used==1)
-               return NULL;
-       card->channel[2].used=1;
-       return &card->channel[2];
-}
-
-static void i810_free_pcm_channel(struct i810_card *card, int channel)
-{
-       card->channel[channel].used=0;
-}
-
-static int i810_valid_spdif_rate ( struct ac97_codec *codec, int rate )
-{
-       unsigned long id = 0L;
-
-       id = (i810_ac97_get(codec, AC97_VENDOR_ID1) << 16);
-       id |= i810_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
-#ifdef DEBUG
-       printk ( "i810_audio: codec = %s, codec_id = 0x%08lx\n", codec->name, id);
-#endif
-       switch ( id ) {
-               case 0x41445361: /* AD1886 */
-                       if (rate == 48000) {
-                               return 1;
-                       }
-                       break;
-               default: /* all other codecs, until we know otherwiae */
-                       if (rate == 48000 || rate == 44100 || rate == 32000) {
-                               return 1;
-                       }
-                       break;
-       }
-       return (0);
-}
-
-/* i810_set_spdif_output
- * 
- *  Configure the S/PDIF output transmitter. When we turn on
- *  S/PDIF, we turn off the analog output. This may not be
- *  the right thing to do.
- *
- *  Assumptions:
- *     The DSP sample rate must already be set to a supported
- *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
- */
-static int i810_set_spdif_output(struct i810_state *state, int slots, int rate)
-{
-       int     vol;
-       int     aud_reg;
-       int     r = 0;
-       struct ac97_codec *codec = state->card->ac97_codec[0];
-
-       if(!codec->codec_ops->digital) {
-               state->card->ac97_status &= ~SPDIF_ON;
-       } else {
-               if ( slots == -1 ) { /* Turn off S/PDIF */
-                       codec->codec_ops->digital(codec, 0, 0, 0);
-                       /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
-                       if ( !(state->card->ac97_status & VOL_MUTED) ) {
-                               aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
-                               i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));
-                       }
-                       state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
-                       return 0;
-               }
-
-               vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
-               state->card->ac97_status = vol & VOL_MUTED;
-               
-               r = codec->codec_ops->digital(codec, slots, rate, 0);
-
-               if(r)
-                       state->card->ac97_status |= SPDIF_ON;
-               else
-                       state->card->ac97_status &= ~SPDIF_ON;
-
-               /* Mute the analog output */
-               /* Should this only mute the PCM volume??? */
-               i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED));
-       }
-       return r;
-}
-
-/* i810_set_dac_channels
- *
- *  Configure the codec's multi-channel DACs
- *
- *  The logic is backwards. Setting the bit to 1 turns off the DAC. 
- *
- *  What about the ICH? We currently configure it using the
- *  SNDCTL_DSP_CHANNELS ioctl.  If we're turnning on the DAC, 
- *  does that imply that we want the ICH set to support
- *  these channels?
- *  
- *  TODO:
- *    vailidate that the codec really supports these DACs
- *    before turning them on. 
- */
-static void i810_set_dac_channels(struct i810_state *state, int channel)
-{
-       int     aud_reg;
-       struct ac97_codec *codec = state->card->ac97_codec[0];
-       
-       /* No codec, no setup */
-       
-       if(codec == NULL)
-               return;
-
-       aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
-       aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
-       state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
-
-       switch ( channel ) {
-               case 2: /* always enabled */
-                       break;
-               case 4:
-                       aud_reg &= ~AC97_EA_PRJ;
-                       state->card->ac97_status |= SURR_ON;
-                       break;
-               case 6:
-                       aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
-                       state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
-                       break;
-               default:
-                       break;
-       }
-       i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
-}
-
-
-/* set playback sample rate */
-static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
-{      
-       struct dmabuf *dmabuf = &state->dmabuf;
-       u32 new_rate;
-       struct ac97_codec *codec=state->card->ac97_codec[0];
-       
-       if(!(state->card->ac97_features&0x0001))
-       {
-               dmabuf->rate = clocking;
-#ifdef DEBUG
-               printk("Asked for %d Hz, but ac97_features says we only do %dHz.  Sorry!\n",
-                      rate,clocking);
-#endif                
-               return clocking;
-       }
-                       
-       if (rate > 48000)
-               rate = 48000;
-       if (rate < 8000)
-               rate = 8000;
-       dmabuf->rate = rate;
-               
-       /*
-        *      Adjust for misclocked crap
-        */
-       rate = ( rate * clocking)/48000;
-       if(strict_clocking && rate < 8000) {
-               rate = 8000;
-               dmabuf->rate = (rate * 48000)/clocking;
-       }
-
-        new_rate=ac97_set_dac_rate(codec, rate);
-       if(new_rate != rate) {
-               dmabuf->rate = (new_rate * 48000)/clocking;
-       }
-#ifdef DEBUG
-       printk("i810_audio: called i810_set_dac_rate : asked for %d, got %d\n", rate, dmabuf->rate);
-#endif
-       rate = new_rate;
-       return dmabuf->rate;
-}
-
-/* set recording sample rate */
-static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       u32 new_rate;
-       struct ac97_codec *codec=state->card->ac97_codec[0];
-       
-       if(!(state->card->ac97_features&0x0001))
-       {
-               dmabuf->rate = clocking;
-               return clocking;
-       }
-                       
-       if (rate > 48000)
-               rate = 48000;
-       if (rate < 8000)
-               rate = 8000;
-       dmabuf->rate = rate;
-
-       /*
-        *      Adjust for misclocked crap
-        */
-        
-       rate = ( rate * clocking)/48000;
-       if(strict_clocking && rate < 8000) {
-               rate = 8000;
-               dmabuf->rate = (rate * 48000)/clocking;
-       }
-
-       new_rate = ac97_set_adc_rate(codec, rate);
-       
-       if(new_rate != rate) {
-               dmabuf->rate = (new_rate * 48000)/clocking;
-               rate = new_rate;
-       }
-#ifdef DEBUG
-       printk("i810_audio: called i810_set_adc_rate : rate = %d/%d\n", dmabuf->rate, rate);
-#endif
-       return dmabuf->rate;
-}
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
-   called with spinlock held! */
-   
-static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned int civ, offset, port, port_picb, bytes = 2;
-       
-       if (!dmabuf->enable)
-               return 0;
-
-       if (rec)
-               port = dmabuf->read_channel->port;
-       else
-               port = dmabuf->write_channel->port;
-
-       if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) {
-               port_picb = port + OFF_SR;
-               bytes = 1;
-       } else
-               port_picb = port + OFF_PICB;
-
-       do {
-               civ = GET_CIV(state->card, port);
-               offset = I810_IOREADW(state->card, port_picb);
-               /* Must have a delay here! */ 
-               if(offset == 0)
-                       udelay(1);
-               /* Reread both registers and make sure that that total
-                * offset from the first reading to the second is 0.
-                * There is an issue with SiS hardware where it will count
-                * picb down to 0, then update civ to the next value,
-                * then set the new picb to fragsize bytes.  We can catch
-                * it between the civ update and the picb update, making
-                * it look as though we are 1 fragsize ahead of where we
-                * are.  The next to we get the address though, it will
-                * be back in the right place, and we will suddenly think
-                * we just went forward dmasize - fragsize bytes, causing
-                * totally stupid *huge* dma overrun messages.  We are
-                * assuming that the 1us delay is more than long enough
-                * that we won't have to worry about the chip still being
-                * out of sync with reality ;-)
-                */
-       } while (civ != GET_CIV(state->card, port) || offset != I810_IOREADW(state->card, port_picb));
-                
-       return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
-               % dmabuf->dmasize);
-}
-
-/* Stop recording (lock held) */
-static inline void __stop_adc(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       struct i810_card *card = state->card;
-
-       dmabuf->enable &= ~ADC_RUNNING;
-       I810_IOWRITEB(0, card, PI_CR);
-       // wait for the card to acknowledge shutdown
-       while( I810_IOREADB(card, PI_CR) != 0 ) ;
-       // now clear any latent interrupt bits (like the halt bit)
-       if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-               I810_IOWRITEB( I810_IOREADB(card, PI_PICB), card, PI_PICB );
-       else
-               I810_IOWRITEB( I810_IOREADB(card, PI_SR), card, PI_SR );
-       I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PI, card, GLOB_STA);
-}
-
-static void stop_adc(struct i810_state *state)
-{
-       struct i810_card *card = state->card;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       __stop_adc(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_adc(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-
-       if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
-           (dmabuf->trigger & PCM_ENABLE_INPUT)) {
-               dmabuf->enable |= ADC_RUNNING;
-               // Interrupt enable, LVI enable, DMA enable
-               I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PI_CR);
-       }
-}
-
-static void start_adc(struct i810_state *state)
-{
-       struct i810_card *card = state->card;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       __start_adc(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop playback (lock held) */
-static inline void __stop_dac(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       struct i810_card *card = state->card;
-
-       dmabuf->enable &= ~DAC_RUNNING;
-       I810_IOWRITEB(0, card, PO_CR);
-       // wait for the card to acknowledge shutdown
-       while( I810_IOREADB(card, PO_CR) != 0 ) ;
-       // now clear any latent interrupt bits (like the halt bit)
-       if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-               I810_IOWRITEB( I810_IOREADB(card, PO_PICB), card, PO_PICB );
-       else
-               I810_IOWRITEB( I810_IOREADB(card, PO_SR), card, PO_SR );
-       I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PO, card, GLOB_STA);
-}
-
-static void stop_dac(struct i810_state *state)
-{
-       struct i810_card *card = state->card;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       __stop_dac(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-}      
-
-static inline void __start_dac(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-
-       if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
-           (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
-               dmabuf->enable |= DAC_RUNNING;
-               // Interrupt enable, LVI enable, DMA enable
-               I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PO_CR);
-       }
-}
-static void start_dac(struct i810_state *state)
-{
-       struct i810_card *card = state->card;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       __start_dac(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/* allocate DMA buffer, playback and recording buffer should be allocated separately */
-static int alloc_dmabuf(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       void *rawbuf= NULL;
-       int order, size;
-       struct page *page, *pend;
-
-       /* If we don't have any oss frag params, then use our default ones */
-       if(dmabuf->ossmaxfrags == 0)
-               dmabuf->ossmaxfrags = 4;
-       if(dmabuf->ossfragsize == 0)
-               dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags;
-       size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-
-       if(dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
-               return 0;
-       /* alloc enough to satisfy the oss params */
-       for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
-               if ( (PAGE_SIZE<<order) > size )
-                       continue;
-               if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
-                                                  PAGE_SIZE << order,
-                                                  &dmabuf->dma_handle)))
-                       break;
-       }
-       if (!rawbuf)
-               return -ENOMEM;
-
-
-#ifdef DEBUG
-       printk("i810_audio: allocated %ld (order = %d) bytes at %p\n",
-              PAGE_SIZE << order, order, rawbuf);
-#endif
-
-       dmabuf->ready  = dmabuf->mapped = 0;
-       dmabuf->rawbuf = rawbuf;
-       dmabuf->buforder = order;
-       
-       /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
-       pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
-       for (page = virt_to_page(rawbuf); page <= pend; page++)
-               SetPageReserved(page);
-
-       return 0;
-}
-
-/* free DMA buffer */
-static void dealloc_dmabuf(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       struct page *page, *pend;
-
-       if (dmabuf->rawbuf) {
-               /* undo marking the pages as reserved */
-               pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
-               for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
-                       ClearPageReserved(page);
-               pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,
-                                   dmabuf->rawbuf, dmabuf->dma_handle);
-       }
-       dmabuf->rawbuf = NULL;
-       dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct i810_state *state, unsigned rec)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       struct i810_channel *c;
-       struct sg_item *sg;
-       unsigned long flags;
-       int ret;
-       unsigned fragint;
-       int i;
-
-       spin_lock_irqsave(&state->card->lock, flags);
-       if(dmabuf->enable & DAC_RUNNING)
-               __stop_dac(state);
-       if(dmabuf->enable & ADC_RUNNING)
-               __stop_adc(state);
-       dmabuf->total_bytes = 0;
-       dmabuf->count = dmabuf->error = 0;
-       dmabuf->swptr = dmabuf->hwptr = 0;
-       spin_unlock_irqrestore(&state->card->lock, flags);
-
-       /* allocate DMA buffer, let alloc_dmabuf determine if we are already
-        * allocated well enough or if we should replace the current buffer
-        * (assuming one is already allocated, if it isn't, then allocate it).
-        */
-       if ((ret = alloc_dmabuf(state)))
-               return ret;
-
-       /* FIXME: figure out all this OSS fragment stuff */
-       /* I did, it now does what it should according to the OSS API.  DL */
-       /* We may not have realloced our dmabuf, but the fragment size to
-        * fragment number ratio may have changed, so go ahead and reprogram
-        * things
-        */
-       dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
-       dmabuf->numfrag = SG_LEN;
-       dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag;
-       dmabuf->fragsamples = dmabuf->fragsize >> 1;
-       dmabuf->fragshift = ffs(dmabuf->fragsize) - 1;
-       dmabuf->userfragsize = dmabuf->ossfragsize;
-       dmabuf->userfrags = dmabuf->dmasize/dmabuf->ossfragsize;
-
-       memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
-
-       if(dmabuf->ossmaxfrags == 4) {
-               fragint = 8;
-       } else if (dmabuf->ossmaxfrags == 8) {
-               fragint = 4;
-       } else if (dmabuf->ossmaxfrags == 16) {
-               fragint = 2;
-       } else {
-               fragint = 1;
-       }
-       /*
-        *      Now set up the ring 
-        */
-       if(dmabuf->read_channel)
-               c = dmabuf->read_channel;
-       else
-               c = dmabuf->write_channel;
-       while(c != NULL) {
-               sg=&c->sg[0];
-               /*
-                *      Load up 32 sg entries and take an interrupt at half
-                *      way (we might want more interrupts later..) 
-                */
-         
-               for(i=0;i<dmabuf->numfrag;i++)
-               {
-                       sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i;
-                       // the card will always be doing 16bit stereo
-                       sg->control=dmabuf->fragsamples;
-                       if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
-                               sg->control <<= 1;
-                       sg->control|=CON_BUFPAD;
-                       // set us up to get IOC interrupts as often as needed to
-                       // satisfy numfrag requirements, no more
-                       if( ((i+1) % fragint) == 0) {
-                               sg->control|=CON_IOC;
-                       }
-                       sg++;
-               }
-               spin_lock_irqsave(&state->card->lock, flags);
-               I810_IOWRITEB(2, state->card, c->port+OFF_CR);   /* reset DMA machine */
-               while( I810_IOREADB(state->card, c->port+OFF_CR) & 0x02 ) ;
-               I810_IOWRITEL((u32)state->card->chandma +
-                   c->num*sizeof(struct i810_channel),
-                   state->card, c->port+OFF_BDBAR);
-               CIV_TO_LVI(state->card, c->port, 0);
-
-               spin_unlock_irqrestore(&state->card->lock, flags);
-
-               if(c != dmabuf->write_channel)
-                       c = dmabuf->write_channel;
-               else
-                       c = NULL;
-       }
-       
-       /* set the ready flag for the dma buffer */
-       dmabuf->ready = 1;
-
-#ifdef DEBUG
-       printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d,\n\tnumfrag = %d, "
-              "fragsize = %d dmasize = %d\n",
-              dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
-              dmabuf->fragsize, dmabuf->dmasize);
-#endif
-
-       return 0;
-}
-
-static void __i810_update_lvi(struct i810_state *state, int rec)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       int x, port;
-       int trigger;
-       int count, fragsize;
-       void (*start)(struct i810_state *);
-
-       count = dmabuf->count;
-       if (rec) {
-               port = dmabuf->read_channel->port;
-               trigger = PCM_ENABLE_INPUT;
-               start = __start_adc;
-               count = dmabuf->dmasize - count;
-       } else {
-               port = dmabuf->write_channel->port;
-               trigger = PCM_ENABLE_OUTPUT;
-               start = __start_dac;
-       }
-
-       /* Do not process partial fragments. */
-       fragsize = dmabuf->fragsize;
-       if (count < fragsize)
-               return;
-
-       /* if we are currently stopped, then our CIV is actually set to our
-        * *last* sg segment and we are ready to wrap to the next.  However,
-        * if we set our LVI to the last sg segment, then it won't wrap to
-        * the next sg segment, it won't even get a start.  So, instead, when
-        * we are stopped, we set both the LVI value and also we increment
-        * the CIV value to the next sg segment to be played so that when
-        * we call start, things will operate properly.  Since the CIV can't
-        * be written to directly for this purpose, we set the LVI to CIV + 1
-        * temporarily.  Once the engine has started we set the LVI to its
-        * final value.
-        */
-       if (!dmabuf->enable && dmabuf->ready) {
-               if (!(dmabuf->trigger & trigger))
-                       return;
-
-               CIV_TO_LVI(state->card, port, 1);
-
-               start(state);
-               while (!(I810_IOREADB(state->card, port + OFF_CR) & ((1<<4) | (1<<2))))
-                       ;
-       }
-
-       /* MASKP2(swptr, fragsize) - 1 is the tail of our transfer */
-       x = MODULOP2(MASKP2(dmabuf->swptr, fragsize) - 1, dmabuf->dmasize);
-       x >>= dmabuf->fragshift;
-       I810_IOWRITEB(x, state->card, port + OFF_LVI);
-}
-
-static void i810_update_lvi(struct i810_state *state, int rec)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-
-       if(!dmabuf->ready)
-               return;
-       spin_lock_irqsave(&state->card->lock, flags);
-       __i810_update_lvi(state, rec);
-       spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void i810_update_ptr(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned hwptr;
-       unsigned fragmask, dmamask;
-       int diff;
-
-       fragmask = MASKP2(~0, dmabuf->fragsize);
-       dmamask = MODULOP2(~0, dmabuf->dmasize);
-
-       /* error handling and process wake up for ADC */
-       if (dmabuf->enable == ADC_RUNNING) {
-               /* update hardware pointer */
-               hwptr = i810_get_dma_addr(state, 1) & fragmask;
-               diff = (hwptr - dmabuf->hwptr) & dmamask;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
-               printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
-               dmabuf->hwptr = hwptr;
-               dmabuf->total_bytes += diff;
-               dmabuf->count += diff;
-               if (dmabuf->count > dmabuf->dmasize) {
-                       /* buffer underrun or buffer overrun */
-                       /* this is normal for the end of a read */
-                       /* only give an error if we went past the */
-                       /* last valid sg entry */
-                       if (GET_CIV(state->card, PI_BASE) !=
-                           GET_LVI(state->card, PI_BASE)) {
-                               printk(KERN_WARNING "i810_audio: DMA overrun on read\n");
-                               dmabuf->error++;
-                       }
-               }
-               if (diff)
-                       wake_up(&dmabuf->wait);
-       }
-       /* error handling and process wake up for DAC */
-       if (dmabuf->enable == DAC_RUNNING) {
-               /* update hardware pointer */
-               hwptr = i810_get_dma_addr(state, 0) & fragmask;
-               diff = (hwptr - dmabuf->hwptr) & dmamask;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
-               printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
-               dmabuf->hwptr = hwptr;
-               dmabuf->total_bytes += diff;
-               dmabuf->count -= diff;
-               if (dmabuf->count < 0) {
-                       /* buffer underrun or buffer overrun */
-                       /* this is normal for the end of a write */
-                       /* only give an error if we went past the */
-                       /* last valid sg entry */
-                       if (GET_CIV(state->card, PO_BASE) !=
-                           GET_LVI(state->card, PO_BASE)) {
-                               printk(KERN_WARNING "i810_audio: DMA overrun on write\n");
-                               printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
-                                       "count %d\n",
-                                       GET_CIV(state->card, PO_BASE),
-                                       GET_LVI(state->card, PO_BASE),
-                                       dmabuf->hwptr, dmabuf->count);
-                               dmabuf->error++;
-                       }
-               }
-               if (diff)
-                       wake_up(&dmabuf->wait);
-       }
-}
-
-static inline int i810_get_free_write_space(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       int free;
-
-       i810_update_ptr(state);
-       // catch underruns during playback
-       if (dmabuf->count < 0) {
-               dmabuf->count = 0;
-               dmabuf->swptr = dmabuf->hwptr;
-       }
-       free = dmabuf->dmasize - dmabuf->count;
-       if(free < 0)
-               return(0);
-       return(free);
-}
-
-static inline int i810_get_available_read_data(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       int avail;
-
-       i810_update_ptr(state);
-       // catch overruns during record
-       if (dmabuf->count > dmabuf->dmasize) {
-               dmabuf->count = dmabuf->dmasize;
-               dmabuf->swptr = dmabuf->hwptr;
-       }
-       avail = dmabuf->count;
-       if(avail < 0)
-               return(0);
-       return(avail);
-}
-
-static inline void fill_partial_frag(struct dmabuf *dmabuf)
-{
-       unsigned fragsize;
-       unsigned swptr, len;
-
-       fragsize = dmabuf->fragsize;
-       swptr = dmabuf->swptr;
-       len = fragsize - MODULOP2(dmabuf->swptr, fragsize);
-       if (len == fragsize)
-               return;
-
-       memset(dmabuf->rawbuf + swptr, '\0', len);
-       dmabuf->swptr = MODULOP2(swptr + len, dmabuf->dmasize);
-       dmabuf->count += len;
-}
-
-static int drain_dac(struct i810_state *state, int signals_allowed)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-       unsigned long tmo;
-       int count;
-
-       if (!dmabuf->ready)
-               return 0;
-       if(dmabuf->mapped) {
-               stop_dac(state);
-               return 0;
-       }
-
-       spin_lock_irqsave(&state->card->lock, flags);
-
-       fill_partial_frag(dmabuf);
-
-       /* 
-        * This will make sure that our LVI is correct, that our
-        * pointer is updated, and that the DAC is running.  We
-        * have to force the setting of dmabuf->trigger to avoid
-        * any possible deadlocks.
-        */
-       dmabuf->trigger = PCM_ENABLE_OUTPUT;
-       __i810_update_lvi(state, 0);
-
-       spin_unlock_irqrestore(&state->card->lock, flags);
-
-       add_wait_queue(&dmabuf->wait, &wait);
-       for (;;) {
-
-               spin_lock_irqsave(&state->card->lock, flags);
-               i810_update_ptr(state);
-               count = dmabuf->count;
-
-               /* It seems that we have to set the current state to
-                * TASK_INTERRUPTIBLE every time to make the process
-                * really go to sleep.  This also has to be *after* the
-                * update_ptr() call because update_ptr is likely to
-                * do a wake_up() which will unset this before we ever
-                * try to sleep, resuling in a tight loop in this code
-                * instead of actually sleeping and waiting for an
-                * interrupt to wake us up!
-                */
-               __set_current_state(signals_allowed ?
-                                   TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
-               spin_unlock_irqrestore(&state->card->lock, flags);
-
-               if (count <= 0)
-                       break;
-
-                if (signal_pending(current) && signals_allowed) {
-                        break;
-                }
-
-               /*
-                * set the timeout to significantly longer than it *should*
-                * take for the DAC to drain the DMA buffer
-                */
-               tmo = (count * HZ) / (dmabuf->rate);
-               if (!schedule_timeout(tmo >= 2 ? tmo : 2)){
-                       printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
-                       count = 0;
-                       break;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&dmabuf->wait, &wait);
-       if(count > 0 && signal_pending(current) && signals_allowed)
-               return -ERESTARTSYS;
-       stop_dac(state);
-       return 0;
-}
-
-static void i810_channel_interrupt(struct i810_card *card)
-{
-       int i, count;
-       
-#ifdef DEBUG_INTERRUPTS
-       printk("CHANNEL ");
-#endif
-       for(i=0;i<NR_HW_CH;i++)
-       {
-               struct i810_state *state = card->states[i];
-               struct i810_channel *c;
-               struct dmabuf *dmabuf;
-               unsigned long port;
-               u16 status;
-               
-               if(!state)
-                       continue;
-               if(!state->dmabuf.ready)
-                       continue;
-               dmabuf = &state->dmabuf;
-               if(dmabuf->enable & DAC_RUNNING) {
-                       c=dmabuf->write_channel;
-               } else if(dmabuf->enable & ADC_RUNNING) {
-                       c=dmabuf->read_channel;
-               } else  /* This can occur going from R/W to close */
-                       continue;
-               
-               port = c->port;
-
-               if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-                       status = I810_IOREADW(card, port + OFF_PICB);
-               else
-                       status = I810_IOREADW(card, port + OFF_SR);
-
-#ifdef DEBUG_INTERRUPTS
-               printk("NUM %d PORT %X IRQ ( ST%d ", c->num, c->port, status);
-#endif
-               if(status & DMA_INT_COMPLETE)
-               {
-                       /* only wake_up() waiters if this interrupt signals
-                        * us being beyond a userfragsize of data open or
-                        * available, and i810_update_ptr() does that for
-                        * us
-                        */
-                       i810_update_ptr(state);
-#ifdef DEBUG_INTERRUPTS
-                       printk("COMP %d ", dmabuf->hwptr /
-                                       dmabuf->fragsize);
-#endif
-               }
-               if(status & (DMA_INT_LVI | DMA_INT_DCH))
-               {
-                       /* wake_up() unconditionally on LVI and DCH */
-                       i810_update_ptr(state);
-                       wake_up(&dmabuf->wait);
-#ifdef DEBUG_INTERRUPTS
-                       if(status & DMA_INT_LVI)
-                               printk("LVI ");
-                       if(status & DMA_INT_DCH)
-                               printk("DCH -");
-#endif
-                       count = dmabuf->count;
-                       if(dmabuf->enable & ADC_RUNNING)
-                               count = dmabuf->dmasize - count;
-                       if (count >= (int)dmabuf->fragsize) {
-                               I810_IOWRITEB(I810_IOREADB(card, port+OFF_CR) | 1, card, port+OFF_CR);
-#ifdef DEBUG_INTERRUPTS
-                               printk(" CONTINUE ");
-#endif
-                       } else {
-                               if (dmabuf->enable & DAC_RUNNING)
-                                       __stop_dac(state);
-                               if (dmabuf->enable & ADC_RUNNING)
-                                       __stop_adc(state);
-                               dmabuf->enable = 0;
-#ifdef DEBUG_INTERRUPTS
-                               printk(" STOP ");
-#endif
-                       }
-               }
-               if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-                       I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_PICB);
-               else
-                       I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_SR);
-       }
-#ifdef DEBUG_INTERRUPTS
-       printk(")\n");
-#endif
-}
-
-static irqreturn_t i810_interrupt(int irq, void *dev_id)
-{
-       struct i810_card *card = dev_id;
-       u32 status;
-
-       spin_lock(&card->lock);
-
-       status = I810_IOREADL(card, GLOB_STA);
-
-       if(!(status & INT_MASK)) 
-       {
-               spin_unlock(&card->lock);
-               return IRQ_NONE;  /* not for us */
-       }
-
-       if(status & (INT_PO|INT_PI|INT_MC))
-               i810_channel_interrupt(card);
-
-       /* clear 'em */
-       I810_IOWRITEL(status & INT_MASK, card, GLOB_STA);
-       spin_unlock(&card->lock);
-       return IRQ_HANDLED;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is
-   waiting to be copied to the user's buffer.  It is filled by the dma
-   machine and drained by this loop. */
-
-static ssize_t i810_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct i810_card *card=state ? state->card : NULL;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       ssize_t ret;
-       unsigned long flags;
-       unsigned int swptr;
-       int cnt;
-       int pending;
-        DECLARE_WAITQUEUE(waita, current);
-
-#ifdef DEBUG2
-       printk("i810_audio: i810_read called, count = %d\n", count);
-#endif
-
-       if (dmabuf->mapped)
-               return -ENXIO;
-       if (dmabuf->enable & DAC_RUNNING)
-               return -ENODEV;
-       if (!dmabuf->read_channel) {
-               dmabuf->ready = 0;
-               dmabuf->read_channel = card->alloc_rec_pcm_channel(card);
-               if (!dmabuf->read_channel) {
-                       return -EBUSY;
-               }
-       }
-       if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-               return ret;
-       if (!access_ok(VERIFY_WRITE, buffer, count))
-               return -EFAULT;
-       ret = 0;
-
-       pending = 0;
-
-        add_wait_queue(&dmabuf->wait, &waita);
-       while (count > 0) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               spin_lock_irqsave(&card->lock, flags);
-                if (PM_SUSPENDED(card)) {
-                        spin_unlock_irqrestore(&card->lock, flags);
-                        schedule();
-                        if (signal_pending(current)) {
-                                if (!ret) ret = -EAGAIN;
-                                break;
-                        }
-                        continue;
-                }
-               cnt = i810_get_available_read_data(state);
-               swptr = dmabuf->swptr;
-               // this is to make the copy_to_user simpler below
-               if(cnt > (dmabuf->dmasize - swptr))
-                       cnt = dmabuf->dmasize - swptr;
-               spin_unlock_irqrestore(&card->lock, flags);
-
-               if (cnt > count)
-                       cnt = count;
-               if (cnt <= 0) {
-                       unsigned long tmo;
-                       /*
-                        * Don't let us deadlock.  The ADC won't start if
-                        * dmabuf->trigger isn't set.  A call to SETTRIGGER
-                        * could have turned it off after we set it to on
-                        * previously.
-                        */
-                       dmabuf->trigger = PCM_ENABLE_INPUT;
-                       /*
-                        * This does three things.  Updates LVI to be correct,
-                        * makes sure the ADC is running, and updates the
-                        * hwptr.
-                        */
-                       i810_update_lvi(state,1);
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (!ret) ret = -EAGAIN;
-                               goto done;
-                       }
-                       /* Set the timeout to how long it would take to fill
-                        * two of our buffers.  If we haven't been woke up
-                        * by then, then we know something is wrong.
-                        */
-                       tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
-                       /* There are two situations when sleep_on_timeout returns, one is when
-                          the interrupt is serviced correctly and the process is waked up by
-                          ISR ON TIME. Another is when timeout is expired, which means that
-                          either interrupt is NOT serviced correctly (pending interrupt) or it
-                          is TOO LATE for the process to be scheduled to run (scheduler latency)
-                          which results in a (potential) buffer overrun. And worse, there is
-                          NOTHING we can do to prevent it. */
-                       if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-#ifdef DEBUG
-                               printk(KERN_ERR "i810_audio: recording schedule timeout, "
-                                      "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-                                      dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
-                                      dmabuf->hwptr, dmabuf->swptr);
-#endif
-                               /* a buffer overrun, we delay the recovery until next time the
-                                  while loop begin and we REALLY have space to record */
-                       }
-                       if (signal_pending(current)) {
-                               ret = ret ? ret : -ERESTARTSYS;
-                               goto done;
-                       }
-                       continue;
-               }
-
-               if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
-                       if (!ret) ret = -EFAULT;
-                       goto done;
-               }
-
-               swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
-
-               spin_lock_irqsave(&card->lock, flags);
-
-                if (PM_SUSPENDED(card)) {
-                        spin_unlock_irqrestore(&card->lock, flags);
-                        continue;
-                }
-               dmabuf->swptr = swptr;
-               pending = dmabuf->count -= cnt;
-               spin_unlock_irqrestore(&card->lock, flags);
-
-               count -= cnt;
-               buffer += cnt;
-               ret += cnt;
-       }
- done:
-       pending = dmabuf->dmasize - pending;
-       if (dmabuf->enable || pending >= dmabuf->userfragsize)
-               i810_update_lvi(state, 1);
-        set_current_state(TASK_RUNNING);
-        remove_wait_queue(&dmabuf->wait, &waita);
-
-       return ret;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
-   the soundcard.  it is drained by the dma machine and filled by this loop. */
-static ssize_t i810_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct i810_card *card=state ? state->card : NULL;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       ssize_t ret;
-       unsigned long flags;
-       unsigned int swptr = 0;
-       int pending;
-       int cnt;
-        DECLARE_WAITQUEUE(waita, current);
-
-#ifdef DEBUG2
-       printk("i810_audio: i810_write called, count = %d\n", count);
-#endif
-
-       if (dmabuf->mapped)
-               return -ENXIO;
-       if (dmabuf->enable & ADC_RUNNING)
-               return -ENODEV;
-       if (!dmabuf->write_channel) {
-               dmabuf->ready = 0;
-               dmabuf->write_channel = card->alloc_pcm_channel(card);
-               if(!dmabuf->write_channel)
-                       return -EBUSY;
-       }
-       if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
-               return ret;
-       if (!access_ok(VERIFY_READ, buffer, count))
-               return -EFAULT;
-       ret = 0;
-
-       pending = 0;
-
-        add_wait_queue(&dmabuf->wait, &waita);
-       while (count > 0) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               spin_lock_irqsave(&state->card->lock, flags);
-                if (PM_SUSPENDED(card)) {
-                        spin_unlock_irqrestore(&card->lock, flags);
-                        schedule();
-                        if (signal_pending(current)) {
-                                if (!ret) ret = -EAGAIN;
-                                break;
-                        }
-                        continue;
-                }
-
-               cnt = i810_get_free_write_space(state);
-               swptr = dmabuf->swptr;
-               /* Bound the maximum size to how much we can copy to the
-                * dma buffer before we hit the end.  If we have more to
-                * copy then it will get done in a second pass of this
-                * loop starting from the beginning of the buffer.
-                */
-               if(cnt > (dmabuf->dmasize - swptr))
-                       cnt = dmabuf->dmasize - swptr;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-
-#ifdef DEBUG2
-               printk(KERN_INFO "i810_audio: i810_write: %d bytes available space\n", cnt);
-#endif
-               if (cnt > count)
-                       cnt = count;
-               if (cnt <= 0) {
-                       unsigned long tmo;
-                       // There is data waiting to be played
-                       /*
-                        * Force the trigger setting since we would
-                        * deadlock with it set any other way
-                        */
-                       dmabuf->trigger = PCM_ENABLE_OUTPUT;
-                       i810_update_lvi(state,0);
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (!ret) ret = -EAGAIN;
-                               goto ret;
-                       }
-                       /* Not strictly correct but works */
-                       tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
-                       /* There are two situations when sleep_on_timeout returns, one is when
-                          the interrupt is serviced correctly and the process is waked up by
-                          ISR ON TIME. Another is when timeout is expired, which means that
-                          either interrupt is NOT serviced correctly (pending interrupt) or it
-                          is TOO LATE for the process to be scheduled to run (scheduler latency)
-                          which results in a (potential) buffer underrun. And worse, there is
-                          NOTHING we can do to prevent it. */
-                       if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-#ifdef DEBUG
-                               printk(KERN_ERR "i810_audio: playback schedule timeout, "
-                                      "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-                                      dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
-                                      dmabuf->hwptr, dmabuf->swptr);
-#endif
-                               /* a buffer underrun, we delay the recovery until next time the
-                                  while loop begin and we REALLY have data to play */
-                               //return ret;
-                       }
-                       if (signal_pending(current)) {
-                               if (!ret) ret = -ERESTARTSYS;
-                               goto ret;
-                       }
-                       continue;
-               }
-               if (copy_from_user(dmabuf->rawbuf+swptr,buffer,cnt)) {
-                       if (!ret) ret = -EFAULT;
-                       goto ret;
-               }
-
-               swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
-
-               spin_lock_irqsave(&state->card->lock, flags);
-                if (PM_SUSPENDED(card)) {
-                        spin_unlock_irqrestore(&card->lock, flags);
-                        continue;
-                }
-
-               dmabuf->swptr = swptr;
-               pending = dmabuf->count += cnt;
-
-               count -= cnt;
-               buffer += cnt;
-               ret += cnt;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-       }
-ret:
-       if (dmabuf->enable || pending >= dmabuf->userfragsize)
-               i810_update_lvi(state, 0);
-        set_current_state(TASK_RUNNING);
-        remove_wait_queue(&dmabuf->wait, &waita);
-
-       return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int i810_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-       unsigned int mask = 0;
-
-       if(!dmabuf->ready)
-               return 0;
-       poll_wait(file, &dmabuf->wait, wait);
-       spin_lock_irqsave(&state->card->lock, flags);
-       if (dmabuf->enable & ADC_RUNNING ||
-           dmabuf->trigger & PCM_ENABLE_INPUT) {
-               if (i810_get_available_read_data(state) >= 
-                   (signed)dmabuf->userfragsize)
-                       mask |= POLLIN | POLLRDNORM;
-       }
-       if (dmabuf->enable & DAC_RUNNING ||
-           dmabuf->trigger & PCM_ENABLE_OUTPUT) {
-               if (i810_get_free_write_space(state) >=
-                   (signed)dmabuf->userfragsize)
-                       mask |= POLLOUT | POLLWRNORM;
-       }
-       spin_unlock_irqrestore(&state->card->lock, flags);
-       return mask;
-}
-
-static int i810_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       int ret = -EINVAL;
-       unsigned long size;
-
-       lock_kernel();
-       if (vma->vm_flags & VM_WRITE) {
-               if (!dmabuf->write_channel &&
-                   (dmabuf->write_channel =
-                    state->card->alloc_pcm_channel(state->card)) == NULL) {
-                       ret = -EBUSY;
-                       goto out;
-               }
-       }
-       if (vma->vm_flags & VM_READ) {
-               if (!dmabuf->read_channel &&
-                   (dmabuf->read_channel = 
-                    state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
-                       ret = -EBUSY;
-                       goto out;
-               }
-       }
-       if ((ret = prog_dmabuf(state, 0)) != 0)
-               goto out;
-
-       ret = -EINVAL;
-       if (vma->vm_pgoff != 0)
-               goto out;
-       size = vma->vm_end - vma->vm_start;
-       if (size > (PAGE_SIZE << dmabuf->buforder))
-               goto out;
-       ret = -EAGAIN;
-       if (remap_pfn_range(vma, vma->vm_start,
-                            virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
-                            size, vma->vm_page_prot))
-               goto out;
-       dmabuf->mapped = 1;
-       dmabuf->trigger = 0;
-       ret = 0;
-#ifdef DEBUG_MMAP
-       printk("i810_audio: mmap'ed %ld bytes of data space\n", size);
-#endif
-out:
-       unlock_kernel();
-       return ret;
-}
-
-static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct i810_channel *c = NULL;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-       audio_buf_info abinfo;
-       count_info cinfo;
-       unsigned int i_glob_cnt;
-       int val = 0, ret;
-       struct ac97_codec *codec = state->card->ac97_codec[0];
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-
-#ifdef DEBUG
-       printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *p : 0);
-#endif
-
-       switch (cmd) 
-       {
-       case OSS_GETVERSION:
-#ifdef DEBUG
-               printk("OSS_GETVERSION\n");
-#endif
-               return put_user(SOUND_VERSION, p);
-
-       case SNDCTL_DSP_RESET:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_RESET\n");
-#endif
-               spin_lock_irqsave(&state->card->lock, flags);
-               if (dmabuf->enable == DAC_RUNNING) {
-                       c = dmabuf->write_channel;
-                       __stop_dac(state);
-               }
-               if (dmabuf->enable == ADC_RUNNING) {
-                       c = dmabuf->read_channel;
-                       __stop_adc(state);
-               }
-               if (c != NULL) {
-                       I810_IOWRITEB(2, state->card, c->port+OFF_CR);   /* reset DMA machine */
-                       while ( I810_IOREADB(state->card, c->port+OFF_CR) & 2 )
-                               cpu_relax();
-                       I810_IOWRITEL((u32)state->card->chandma +
-                           c->num*sizeof(struct i810_channel),
-                           state->card, c->port+OFF_BDBAR);
-                       CIV_TO_LVI(state->card, c->port, 0);
-               }
-
-               spin_unlock_irqrestore(&state->card->lock, flags);
-               synchronize_irq(state->card->pci_dev->irq);
-               dmabuf->ready = 0;
-               dmabuf->swptr = dmabuf->hwptr = 0;
-               dmabuf->count = dmabuf->total_bytes = 0;
-               return 0;
-
-       case SNDCTL_DSP_SYNC:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SYNC\n");
-#endif
-               if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
-                       return 0;
-               if((val = drain_dac(state, 1)))
-                       return val;
-               dmabuf->total_bytes = 0;
-               return 0;
-
-       case SNDCTL_DSP_SPEED: /* set smaple rate */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SPEED\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-               if (val >= 0) {
-                       if (file->f_mode & FMODE_WRITE) {
-                               if ( (state->card->ac97_status & SPDIF_ON) ) {  /* S/PDIF Enabled */
-                                       /* AD1886 only supports 48000, need to check that */
-                                       if ( i810_valid_spdif_rate ( codec, val ) ) {
-                                               /* Set DAC rate */
-                                               i810_set_spdif_output ( state, -1, 0 );
-                                               stop_dac(state);
-                                               dmabuf->ready = 0;
-                                               spin_lock_irqsave(&state->card->lock, flags);
-                                               i810_set_dac_rate(state, val);
-                                               spin_unlock_irqrestore(&state->card->lock, flags);
-                                               /* Set S/PDIF transmitter rate. */
-                                               i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, val );
-                                               if ( ! (state->card->ac97_status & SPDIF_ON) ) {
-                                                       val = dmabuf->rate;
-                                               }
-                                       } else { /* Not a valid rate for S/PDIF, ignore it */
-                                               val = dmabuf->rate;
-                                       }
-                               } else {
-                                       stop_dac(state);
-                                       dmabuf->ready = 0;
-                                       spin_lock_irqsave(&state->card->lock, flags);
-                                       i810_set_dac_rate(state, val);
-                                       spin_unlock_irqrestore(&state->card->lock, flags);
-                               }
-                       }
-                       if (file->f_mode & FMODE_READ) {
-                               stop_adc(state);
-                               dmabuf->ready = 0;
-                               spin_lock_irqsave(&state->card->lock, flags);
-                               i810_set_adc_rate(state, val);
-                               spin_unlock_irqrestore(&state->card->lock, flags);
-                       }
-               }
-               return put_user(dmabuf->rate, p);
-
-       case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_STEREO\n");
-#endif
-               if (dmabuf->enable & DAC_RUNNING) {
-                       stop_dac(state);
-               }
-               if (dmabuf->enable & ADC_RUNNING) {
-                       stop_adc(state);
-               }
-               return put_user(1, p);
-
-       case SNDCTL_DSP_GETBLKSIZE:
-               if (file->f_mode & FMODE_WRITE) {
-                       if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
-                               return val;
-               }
-               if (file->f_mode & FMODE_READ) {
-                       if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
-                               return val;
-               }
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
-#endif
-               return put_user(dmabuf->userfragsize, p);
-
-       case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETFMTS\n");
-#endif
-               return put_user(AFMT_S16_LE, p);
-
-       case SNDCTL_DSP_SETFMT: /* Select sample format */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SETFMT\n");
-#endif
-               return put_user(AFMT_S16_LE, p);
-
-       case SNDCTL_DSP_CHANNELS:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_CHANNELS\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-
-               if (val > 0) {
-                       if (dmabuf->enable & DAC_RUNNING) {
-                               stop_dac(state);
-                       }
-                       if (dmabuf->enable & ADC_RUNNING) {
-                               stop_adc(state);
-                       }
-               } else {
-                       return put_user(state->card->channels, p);
-               }
-
-               /* ICH and ICH0 only support 2 channels */
-               if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AA_5
-                    || state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AB_5) 
-                       return put_user(2, p);
-       
-               /* Multi-channel support was added with ICH2. Bits in */
-               /* Global Status and Global Control register are now  */
-               /* used to indicate this.                             */
-
-                i_glob_cnt = I810_IOREADL(state->card, GLOB_CNT);
-
-               /* Current # of channels enabled */
-               if ( i_glob_cnt & 0x0100000 )
-                       ret = 4;
-               else if ( i_glob_cnt & 0x0200000 )
-                       ret = 6;
-               else
-                       ret = 2;
-
-               switch ( val ) {
-                       case 2: /* 2 channels is always supported */
-                               I810_IOWRITEL(i_glob_cnt & 0xffcfffff,
-                                    state->card, GLOB_CNT);
-                               /* Do we need to change mixer settings????  */
-                               break;
-                       case 4: /* Supported on some chipsets, better check first */
-                               if ( state->card->channels >= 4 ) {
-                                       I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x100000,
-                                             state->card, GLOB_CNT);
-                                       /* Do we need to change mixer settings??? */
-                               } else {
-                                       val = ret;
-                               }
-                               break;
-                       case 6: /* Supported on some chipsets, better check first */
-                               if ( state->card->channels >= 6 ) {
-                                       I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x200000,
-                                             state->card, GLOB_CNT);
-                                       /* Do we need to change mixer settings??? */
-                               } else {
-                                       val = ret;
-                               }
-                               break;
-                       default: /* nothing else is ever supported by the chipset */
-                               val = ret;
-                               break;
-               }
-
-               return put_user(val, p);
-
-       case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */
-               /* we update the swptr to the end of the last sg segment then return */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_POST\n");
-#endif
-               if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
-                       return 0;
-               if((dmabuf->swptr % dmabuf->fragsize) != 0) {
-                       val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
-                       dmabuf->swptr += val;
-                       dmabuf->count += val;
-               }
-               return 0;
-
-       case SNDCTL_DSP_SUBDIVIDE:
-               if (dmabuf->subdivision)
-                       return -EINVAL;
-               if (get_user(val, p))
-                       return -EFAULT;
-               if (val != 1 && val != 2 && val != 4)
-                       return -EINVAL;
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
-#endif
-               dmabuf->subdivision = val;
-               dmabuf->ready = 0;
-               return 0;
-
-       case SNDCTL_DSP_SETFRAGMENT:
-               if (get_user(val, p))
-                       return -EFAULT;
-
-               dmabuf->ossfragsize = 1<<(val & 0xffff);
-               dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
-               if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
-                       return -EINVAL;
-               /*
-                * Bound the frag size into our allowed range of 256 - 4096
-                */
-               if (dmabuf->ossfragsize < 256)
-                       dmabuf->ossfragsize = 256;
-               else if (dmabuf->ossfragsize > 4096)
-                       dmabuf->ossfragsize = 4096;
-               /*
-                * The numfrags could be something reasonable, or it could
-                * be 0xffff meaning "Give me as much as possible".  So,
-                * we check the numfrags * fragsize doesn't exceed our
-                * 64k buffer limit, nor is it less than our 8k minimum.
-                * If it fails either one of these checks, then adjust the
-                * number of fragments, not the size of them.  It's OK if
-                * our number of fragments doesn't equal 32 or anything
-                * like our hardware based number now since we are using
-                * a different frag count for the hardware.  Before we get
-                * into this though, bound the maxfrags to avoid overflow
-                * issues.  A reasonable bound would be 64k / 256 since our
-                * maximum buffer size is 64k and our minimum frag size is
-                * 256.  On the other end, our minimum buffer size is 8k and
-                * our maximum frag size is 4k, so the lower bound should
-                * be 2.
-                */
-
-               if(dmabuf->ossmaxfrags > 256)
-                       dmabuf->ossmaxfrags = 256;
-               else if (dmabuf->ossmaxfrags < 2)
-                       dmabuf->ossmaxfrags = 2;
-
-               val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-               while (val < 8192) {
-                   val <<= 1;
-                   dmabuf->ossmaxfrags <<= 1;
-               }
-               while (val > 65536) {
-                   val >>= 1;
-                   dmabuf->ossmaxfrags >>= 1;
-               }
-               dmabuf->ready = 0;
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
-                       dmabuf->ossfragsize, dmabuf->ossmaxfrags);
-#endif
-
-               return 0;
-
-       case SNDCTL_DSP_GETOSPACE:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-                       return val;
-               spin_lock_irqsave(&state->card->lock, flags);
-               i810_update_ptr(state);
-               abinfo.fragsize = dmabuf->userfragsize;
-               abinfo.fragstotal = dmabuf->userfrags;
-               if (dmabuf->mapped)
-                       abinfo.bytes = dmabuf->dmasize;
-               else
-                       abinfo.bytes = i810_get_free_write_space(state);
-               abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes,
-                       abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
-#endif
-               return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_GETOPTR:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-                       return val;
-               spin_lock_irqsave(&state->card->lock, flags);
-               val = i810_get_free_write_space(state);
-               cinfo.bytes = dmabuf->total_bytes;
-               cinfo.ptr = dmabuf->hwptr;
-               cinfo.blocks = val/dmabuf->userfragsize;
-               if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
-                       dmabuf->count += val;
-                       dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
-                       __i810_update_lvi(state, 0);
-               }
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
-                       cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
-               return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_GETISPACE:
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
-                       return val;
-               spin_lock_irqsave(&state->card->lock, flags);
-               abinfo.bytes = i810_get_available_read_data(state);
-               abinfo.fragsize = dmabuf->userfragsize;
-               abinfo.fragstotal = dmabuf->userfrags;
-               abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes,
-                       abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
-#endif
-               return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_GETIPTR:
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-                       return val;
-               spin_lock_irqsave(&state->card->lock, flags);
-               val = i810_get_available_read_data(state);
-               cinfo.bytes = dmabuf->total_bytes;
-               cinfo.blocks = val/dmabuf->userfragsize;
-               cinfo.ptr = dmabuf->hwptr;
-               if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
-                       dmabuf->count -= val;
-                       dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
-                       __i810_update_lvi(state, 1);
-               }
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
-                       cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
-               return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_NONBLOCK:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_NONBLOCK\n");
-#endif
-               file->f_flags |= O_NONBLOCK;
-               return 0;
-
-       case SNDCTL_DSP_GETCAPS:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETCAPS\n");
-#endif
-           return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,
-                           p);
-
-       case SNDCTL_DSP_GETTRIGGER:
-               val = 0;
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
-#endif
-               return put_user(dmabuf->trigger, p);
-
-       case SNDCTL_DSP_SETTRIGGER:
-               if (get_user(val, p))
-                       return -EFAULT;
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
-#endif
-               /* silently ignore invalid PCM_ENABLE_xxx bits,
-                * like the other drivers do
-                */
-               if (!(file->f_mode & FMODE_READ ))
-                       val &= ~PCM_ENABLE_INPUT;
-               if (!(file->f_mode & FMODE_WRITE ))
-                       val &= ~PCM_ENABLE_OUTPUT;
-               if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
-                       stop_adc(state);
-               }
-               if((file->f_mode & FMODE_WRITE) && !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
-                       stop_dac(state);
-               }
-               dmabuf->trigger = val;
-               if((val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
-                       if (!dmabuf->write_channel) {
-                               dmabuf->ready = 0;
-                               dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
-                               if (!dmabuf->write_channel)
-                                       return -EBUSY;
-                       }
-                       if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
-                               return ret;
-                       if (dmabuf->mapped) {
-                               spin_lock_irqsave(&state->card->lock, flags);
-                               i810_update_ptr(state);
-                               dmabuf->count = 0;
-                               dmabuf->swptr = dmabuf->hwptr;
-                               dmabuf->count = i810_get_free_write_space(state);
-                               dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
-                               spin_unlock_irqrestore(&state->card->lock, flags);
-                       }
-                       i810_update_lvi(state, 0);
-                       start_dac(state);
-               }
-               if((val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
-                       if (!dmabuf->read_channel) {
-                               dmabuf->ready = 0;
-                               dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
-                               if (!dmabuf->read_channel)
-                                       return -EBUSY;
-                       }
-                       if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-                               return ret;
-                       if (dmabuf->mapped) {
-                               spin_lock_irqsave(&state->card->lock, flags);
-                               i810_update_ptr(state);
-                               dmabuf->swptr = dmabuf->hwptr;
-                               dmabuf->count = 0;
-                               spin_unlock_irqrestore(&state->card->lock, flags);
-                       }
-                       i810_update_lvi(state, 1);
-                       start_adc(state);
-               }
-               return 0;
-
-       case SNDCTL_DSP_SETDUPLEX:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SETDUPLEX\n");
-#endif
-               return -EINVAL;
-
-       case SNDCTL_DSP_GETODELAY:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               spin_lock_irqsave(&state->card->lock, flags);
-               i810_update_ptr(state);
-               val = dmabuf->count;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
-#endif
-               return put_user(val, p);
-
-       case SOUND_PCM_READ_RATE:
-#ifdef DEBUG
-               printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
-#endif
-               return put_user(dmabuf->rate, p);
-
-       case SOUND_PCM_READ_CHANNELS:
-#ifdef DEBUG
-               printk("SOUND_PCM_READ_CHANNELS\n");
-#endif
-               return put_user(2, p);
-
-       case SOUND_PCM_READ_BITS:
-#ifdef DEBUG
-               printk("SOUND_PCM_READ_BITS\n");
-#endif
-               return put_user(AFMT_S16_LE, p);
-
-       case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SETSPDIF\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-
-               /* Check to make sure the codec supports S/PDIF transmitter */
-
-               if((state->card->ac97_features & 4)) {
-                       /* mask out the transmitter speed bits so the user can't set them */
-                       val &= ~0x3000;
-
-                       /* Add the current transmitter speed bits to the passed value */
-                       ret = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
-                       val |= (ret & 0x3000);
-
-                       i810_ac97_set(codec, AC97_SPDIF_CONTROL, val);
-                       if(i810_ac97_get(codec, AC97_SPDIF_CONTROL) != val ) {
-                               printk(KERN_ERR "i810_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
-                               return -EFAULT;
-                       }
-               }
-#ifdef DEBUG
-               else 
-                       printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
-#endif
-               return put_user(val, p);
-
-       case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETSPDIF\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-
-               /* Check to make sure the codec supports S/PDIF transmitter */
-
-               if(!(state->card->ac97_features & 4)) {
-#ifdef DEBUG
-                       printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
-#endif
-                       val = 0;
-               } else {
-                       val = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
-               }
-               //return put_user((val & 0xcfff), p);
-               return put_user(val, p);
-                       
-       case SNDCTL_DSP_GETCHANNELMASK:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETCHANNELMASK\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-               
-               /* Based on AC'97 DAC support, not ICH hardware */
-               val = DSP_BIND_FRONT;
-               if ( state->card->ac97_features & 0x0004 )
-                       val |= DSP_BIND_SPDIF;
-
-               if ( state->card->ac97_features & 0x0080 )
-                       val |= DSP_BIND_SURR;
-               if ( state->card->ac97_features & 0x0140 )
-                       val |= DSP_BIND_CENTER_LFE;
-
-               return put_user(val, p);
-
-       case SNDCTL_DSP_BIND_CHANNEL:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_BIND_CHANNEL\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-               if ( val == DSP_BIND_QUERY ) {
-                       val = DSP_BIND_FRONT; /* Always report this as being enabled */
-                       if ( state->card->ac97_status & SPDIF_ON ) 
-                               val |= DSP_BIND_SPDIF;
-                       else {
-                               if ( state->card->ac97_status & SURR_ON )
-                                       val |= DSP_BIND_SURR;
-                               if ( state->card->ac97_status & CENTER_LFE_ON )
-                                       val |= DSP_BIND_CENTER_LFE;
-                       }
-               } else {  /* Not a query, set it */
-                       if (!(file->f_mode & FMODE_WRITE))
-                               return -EINVAL;
-                       if ( dmabuf->enable == DAC_RUNNING ) {
-                               stop_dac(state);
-                       }
-                       if ( val & DSP_BIND_SPDIF ) {  /* Turn on SPDIF */
-                               /*  Ok, this should probably define what slots
-                                *  to use. For now, we'll only set it to the
-                                *  defaults:
-                                * 
-                                *   non multichannel codec maps to slots 3&4
-                                *   2 channel codec maps to slots 7&8
-                                *   4 channel codec maps to slots 6&9
-                                *   6 channel codec maps to slots 10&11
-                                *
-                                *  there should be some way for the app to
-                                *  select the slot assignment.
-                                */
-       
-                               i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, dmabuf->rate );
-                               if ( !(state->card->ac97_status & SPDIF_ON) )
-                                       val &= ~DSP_BIND_SPDIF;
-                       } else {
-                               int mask;
-                               int channels;
-
-                               /* Turn off S/PDIF if it was on */
-                               if ( state->card->ac97_status & SPDIF_ON ) 
-                                       i810_set_spdif_output ( state, -1, 0 );
-                               
-                               mask = val & (DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE);
-                               switch (mask) {
-                                       case DSP_BIND_FRONT:
-                                               channels = 2;
-                                               break;
-                                       case DSP_BIND_FRONT|DSP_BIND_SURR:
-                                               channels = 4;
-                                               break;
-                                       case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
-                                               channels = 6;
-                                               break;
-                                       default:
-                                               val = DSP_BIND_FRONT;
-                                               channels = 2;
-                                               break;
-                               }
-                               i810_set_dac_channels ( state, channels );
-
-                               /* check that they really got turned on */
-                               if (!(state->card->ac97_status & SURR_ON))
-                                       val &= ~DSP_BIND_SURR;
-                               if (!(state->card->ac97_status & CENTER_LFE_ON))
-                                       val &= ~DSP_BIND_CENTER_LFE;
-                       }
-               }
-               return put_user(val, p);
-               
-       case SNDCTL_DSP_MAPINBUF:
-       case SNDCTL_DSP_MAPOUTBUF:
-       case SNDCTL_DSP_SETSYNCRO:
-       case SOUND_PCM_WRITE_FILTER:
-       case SOUND_PCM_READ_FILTER:
-#ifdef DEBUG
-               printk("SNDCTL_* -EINVAL\n");
-#endif
-               return -EINVAL;
-       }
-       return -EINVAL;
-}
-
-static int i810_open(struct inode *inode, struct file *file)
-{
-       int i = 0;
-       struct i810_card *card = devs;
-       struct i810_state *state = NULL;
-       struct dmabuf *dmabuf = NULL;
-
-       /* find an avaiable virtual channel (instance of /dev/dsp) */
-       while (card != NULL) {
-               /*
-                * If we are initializing and then fail, card could go
-                * away unuexpectedly while we are in the for() loop.
-                * So, check for card on each iteration before we check
-                * for card->initializing to avoid a possible oops.
-                * This usually only matters for times when the driver is
-                * autoloaded by kmod.
-                */
-               for (i = 0; i < 50 && card && card->initializing; i++) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(HZ/20);
-               }
-               for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
-                       if (card->states[i] == NULL) {
-                               state = card->states[i] = (struct i810_state *)
-                                       kzalloc(sizeof(struct i810_state), GFP_KERNEL);
-                               if (state == NULL)
-                                       return -ENOMEM;
-                               dmabuf = &state->dmabuf;
-                               goto found_virt;
-                       }
-               }
-               card = card->next;
-       }
-       /* no more virtual channel avaiable */
-       if (!state)
-               return -ENODEV;
-
-found_virt:
-       /* initialize the virtual channel */
-       state->virt = i;
-       state->card = card;
-       state->magic = I810_STATE_MAGIC;
-       init_waitqueue_head(&dmabuf->wait);
-       mutex_init(&state->open_mutex);
-       file->private_data = state;
-       dmabuf->trigger = 0;
-
-       /* allocate hardware channels */
-       if(file->f_mode & FMODE_READ) {
-               if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) {
-                       kfree (card->states[i]);
-                       card->states[i] = NULL;
-                       return -EBUSY;
-               }
-               dmabuf->trigger |= PCM_ENABLE_INPUT;
-               i810_set_adc_rate(state, 8000);
-       }
-       if(file->f_mode & FMODE_WRITE) {
-               if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
-                       /* make sure we free the record channel allocated above */
-                       if(file->f_mode & FMODE_READ)
-                               card->free_pcm_channel(card,dmabuf->read_channel->num);
-                       kfree (card->states[i]);
-                       card->states[i] = NULL;
-                       return -EBUSY;
-               }
-               /* Initialize to 8kHz?  What if we don't support 8kHz? */
-               /*  Let's change this to check for S/PDIF stuff */
-       
-               dmabuf->trigger |= PCM_ENABLE_OUTPUT;
-               if ( spdif_locked ) {
-                       i810_set_dac_rate(state, spdif_locked);
-                       i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
-               } else {
-                       i810_set_dac_rate(state, 8000);
-                       /* Put the ACLink in 2 channel mode by default */
-                       i = I810_IOREADL(card, GLOB_CNT);
-                       I810_IOWRITEL(i & 0xffcfffff, card, GLOB_CNT);
-               }
-       }
-               
-       /* set default sample format. According to OSS Programmer's Guide  /dev/dsp
-          should be default to unsigned 8-bits, mono, with sample rate 8kHz and
-          /dev/dspW will accept 16-bits sample, but we don't support those so we
-          set it immediately to stereo and 16bit, which is all we do support */
-       dmabuf->fmt |= I810_FMT_16BIT | I810_FMT_STEREO;
-       dmabuf->ossfragsize = 0;
-       dmabuf->ossmaxfrags  = 0;
-       dmabuf->subdivision  = 0;
-
-       state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
-       return nonseekable_open(inode, file);
-}
-
-static int i810_release(struct inode *inode, struct file *file)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct i810_card *card = state->card;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-
-       lock_kernel();
-
-       /* stop DMA state machine and free DMA buffers/channels */
-       if(dmabuf->trigger & PCM_ENABLE_OUTPUT) {
-               drain_dac(state, 0);
-       }
-       if(dmabuf->trigger & PCM_ENABLE_INPUT) {
-               stop_adc(state);
-       }
-       spin_lock_irqsave(&card->lock, flags);
-       dealloc_dmabuf(state);
-       if (file->f_mode & FMODE_WRITE) {
-               state->card->free_pcm_channel(state->card, dmabuf->write_channel->num);
-       }
-       if (file->f_mode & FMODE_READ) {
-               state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
-       }
-
-       state->card->states[state->virt] = NULL;
-       kfree(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-       unlock_kernel();
-
-       return 0;
-}
-
-static /*const*/ struct file_operations i810_audio_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .read           = i810_read,
-       .write          = i810_write,
-       .poll           = i810_poll,
-       .ioctl          = i810_ioctl,
-       .mmap           = i810_mmap,
-       .open           = i810_open,
-       .release        = i810_release,
-};
-
-/* Write AC97 codec registers */
-
-static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg)
-{
-       struct i810_card *card = dev->private_data;
-       int count = 100;
-       u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-       
-       while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
-               udelay(1);
-       
-#ifdef DEBUG_MMIO
-       {
-               u16 ans = readw(card->ac97base_mmio + reg_set);
-               printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans);
-               return ans;
-       }
-#else
-       return readw(card->ac97base_mmio + reg_set);
-#endif
-}
-
-static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg)
-{
-       struct i810_card *card = dev->private_data;
-       int count = 100;
-       u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-       
-       while(count-- && (I810_IOREADB(card, CAS) & 1)) 
-               udelay(1);
-       
-       return inw(card->ac97base + reg_set);
-}
-
-static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data)
-{
-       struct i810_card *card = dev->private_data;
-       int count = 100;
-       u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-       
-       while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
-               udelay(1);
-       
-       writew(data, card->ac97base_mmio + reg_set);
-
-#ifdef DEBUG_MMIO
-       printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff);
-#endif
-}
-
-static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data)
-{
-       struct i810_card *card = dev->private_data;
-       int count = 100;
-       u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-       
-       while(count-- && (I810_IOREADB(card, CAS) & 1)) 
-               udelay(1);
-       
-        outw(data, card->ac97base + reg_set);
-}
-
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
-{
-       struct i810_card *card = dev->private_data;
-       u16 ret;
-       
-       spin_lock(&card->ac97_lock);
-       if (card->use_mmio) {
-               ret = i810_ac97_get_mmio(dev, reg);
-       }
-       else {
-               ret = i810_ac97_get_io(dev, reg);
-       }
-       spin_unlock(&card->ac97_lock);
-       
-       return ret;
-}
-
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
-{
-       struct i810_card *card = dev->private_data;
-       
-       spin_lock(&card->ac97_lock);
-       if (card->use_mmio) {
-               i810_ac97_set_mmio(dev, reg, data);
-       }
-       else {
-               i810_ac97_set_io(dev, reg, data);
-       }
-       spin_unlock(&card->ac97_lock);
-}
-
-
-/* OSS /dev/mixer file operation methods */
-
-static int i810_open_mixdev(struct inode *inode, struct file *file)
-{
-       int i;
-       int minor = iminor(inode);
-       struct i810_card *card = devs;
-
-       for (card = devs; card != NULL; card = card->next) {
-               /*
-                * If we are initializing and then fail, card could go
-                * away unuexpectedly while we are in the for() loop.
-                * So, check for card on each iteration before we check
-                * for card->initializing to avoid a possible oops.
-                * This usually only matters for times when the driver is
-                * autoloaded by kmod.
-                */
-               for (i = 0; i < 50 && card && card->initializing; i++) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(HZ/20);
-               }
-               for (i = 0; i < NR_AC97 && card && !card->initializing; i++) 
-                       if (card->ac97_codec[i] != NULL &&
-                           card->ac97_codec[i]->dev_mixer == minor) {
-                               file->private_data = card->ac97_codec[i];
-                               return nonseekable_open(inode, file);
-                       }
-       }
-       return -ENODEV;
-}
-
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
-                               unsigned long arg)
-{
-       struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
-       return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static /*const*/ struct file_operations i810_mixer_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .ioctl          = i810_ioctl_mixdev,
-       .open           = i810_open_mixdev,
-};
-
-/* AC97 codec initialisation.  These small functions exist so we don't
-   duplicate code between module init and apm resume */
-
-static inline int i810_ac97_exists(struct i810_card *card, int ac97_number)
-{
-       u32 reg = I810_IOREADL(card, GLOB_STA);
-       switch (ac97_number) {
-       case 0:
-               return reg & (1<<8);
-       case 1: 
-               return reg & (1<<9);
-       case 2:
-               return reg & (1<<28);
-       }
-       return 0;
-}
-
-static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec)
-{
-       i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
-       i810_ac97_set(codec,AC97_EXTENDED_STATUS,
-                     i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800);
-       
-       return (i810_ac97_get(codec, AC97_EXTENDED_STATUS)&1);
-}
-
-
-static int i810_ac97_probe_and_powerup(struct i810_card *card,struct ac97_codec *codec)
-{
-       /* Returns 0 on failure */
-       int i;
-
-       if (ac97_probe_codec(codec) == 0) return 0;
-       
-       /* power it all up */
-       i810_ac97_set(codec, AC97_POWER_CONTROL,
-                     i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
-
-       /* wait for analog ready */
-       for (i=100; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--)
-       {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ/20);
-       } 
-       return i;
-}
-
-static int is_new_ich(u16 pci_id)
-{
-       switch (pci_id) {
-       case PCI_DEVICE_ID_INTEL_82801DB_5:
-       case PCI_DEVICE_ID_INTEL_82801EB_5:
-       case PCI_DEVICE_ID_INTEL_ESB_5:
-       case PCI_DEVICE_ID_INTEL_ICH6_18:
-               return 1;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static inline int ich_use_mmio(struct i810_card *card)
-{
-       return is_new_ich(card->pci_id) && card->use_mmio;
-}
-
-/**
- *     i810_ac97_power_up_bus  -       bring up AC97 link
- *     @card : ICH audio device to power up
- *
- *     Bring up the ACLink AC97 codec bus
- */
-static int i810_ac97_power_up_bus(struct i810_card *card)
-{      
-       u32 reg = I810_IOREADL(card, GLOB_CNT);
-       int i;
-       int primary_codec_id = 0;
-
-       if((reg&2)==0)  /* Cold required */
-               reg|=2;
-       else
-               reg|=4; /* Warm */
-               
-       reg&=~8;        /* ACLink on */
-       
-       /* At this point we deassert AC_RESET # */
-       I810_IOWRITEL(reg , card, GLOB_CNT);
-
-       /* We must now allow time for the Codec initialisation.
-          600mS is the specified time */
-               
-       for(i=0;i<10;i++)
-       {
-               if((I810_IOREADL(card, GLOB_CNT)&4)==0)
-                       break;
-
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ/20);
-       }
-       if(i==10)
-       {
-               printk(KERN_ERR "i810_audio: AC'97 reset failed.\n");
-               return 0;
-       }
-
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ/2);
-
-       /*
-        *      See if the primary codec comes ready. This must happen
-        *      before we start doing DMA stuff
-        */     
-       /* see i810_ac97_init for the next 10 lines (jsaw) */
-       if (card->use_mmio)
-               readw(card->ac97base_mmio);
-       else
-               inw(card->ac97base);
-       if (ich_use_mmio(card)) {
-               primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
-               printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
-                      primary_codec_id);
-       }
-
-       if(! i810_ac97_exists(card, primary_codec_id))
-       {
-               printk(KERN_INFO "i810_audio: Codec not ready.. wait.. ");
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ);   /* actually 600mS by the spec */
-
-               if(i810_ac97_exists(card, primary_codec_id))
-                       printk("OK\n");
-               else 
-                       printk("no response.\n");
-       }
-       if (card->use_mmio)
-               readw(card->ac97base_mmio);
-       else
-               inw(card->ac97base);
-       return 1;
-}
-
-static int __devinit i810_ac97_init(struct i810_card *card)
-{
-       int num_ac97 = 0;
-       int ac97_id;
-       int total_channels = 0;
-       int nr_ac97_max = card_cap[card->pci_id_internal].nr_ac97;
-       struct ac97_codec *codec;
-       u16 eid;
-       u32 reg;
-
-       if(!i810_ac97_power_up_bus(card)) return 0;
-
-       /* Number of channels supported */
-       /* What about the codec?  Just because the ICH supports */
-       /* multiple channels doesn't mean the codec does.       */
-       /* we'll have to modify this in the codec section below */
-       /* to reflect what the codec has.                       */
-       /* ICH and ICH0 only support 2 channels so don't bother */
-       /* to check....                                         */
-
-       card->channels = 2;
-       reg = I810_IOREADL(card, GLOB_STA);
-       if ( reg & 0x0200000 )
-               card->channels = 6;
-       else if ( reg & 0x0100000 )
-               card->channels = 4;
-       printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels);
-       printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n");
-       reg = I810_IOREADL(card, GLOB_CNT);
-       I810_IOWRITEL(reg & 0xffcfffff, card, GLOB_CNT);
-               
-       for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) 
-               card->ac97_codec[num_ac97] = NULL;
-
-       /*@FIXME I don't know, if I'm playing to safe here... (jsaw) */
-       if ((nr_ac97_max > 2) && !card->use_mmio) nr_ac97_max = 2;
-
-       for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) {
-               /* codec reset */
-               printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97);
-               if (card->use_mmio)
-                       readw(card->ac97base_mmio + 0x80*num_ac97);
-               else
-                       inw(card->ac97base + 0x80*num_ac97);
-
-               /* If we have the SDATA_IN Map Register, as on ICH4, we
-                  do not loop thru all possible codec IDs but thru all 
-                  possible IO channels. Bit 0:1 of SDM then holds the 
-                  last codec ID spoken to. 
-               */
-               if (ich_use_mmio(card)) {
-                       ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
-                       printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n",
-                              num_ac97, ac97_id);
-               }
-               else {
-                       ac97_id = num_ac97;
-               }
-
-               /* The ICH programmer's reference says you should   */
-               /* check the ready status before probing. So we chk */
-               /*   What do we do if it's not ready?  Wait and try */
-               /*   again, or abort?                               */
-               if (!i810_ac97_exists(card, ac97_id)) {
-                       if(num_ac97 == 0)
-                               printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
-               }
-               
-               if ((codec = ac97_alloc_codec()) == NULL)
-                       return -ENOMEM;
-
-               /* initialize some basic codec information, other fields will be filled
-                  in ac97_probe_codec */
-               codec->private_data = card;
-               codec->id = ac97_id;
-               card->ac97_id_map[ac97_id] = num_ac97 * 0x80;
-
-               if (card->use_mmio) {   
-                       codec->codec_read = i810_ac97_get_mmio;
-                       codec->codec_write = i810_ac97_set_mmio;
-               }
-               else {
-                       codec->codec_read = i810_ac97_get_io;
-                       codec->codec_write = i810_ac97_set_io;
-               }
-       
-               if(!i810_ac97_probe_and_powerup(card,codec)) {
-                       printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id);
-                       ac97_release_codec(codec);
-                       break;  /* it didn't work */
-               }
-               /* Store state information about S/PDIF transmitter */
-               card->ac97_status = 0;
-               
-               /* Don't attempt to get eid until powerup is complete */
-               eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-
-               if(eid==0xFFFF)
-               {
-                       printk(KERN_WARNING "i810_audio: no codec attached ?\n");
-                       ac97_release_codec(codec);
-                       break;
-               }
-               
-               /* Check for an AC97 1.0 soft modem (ID1) */
-               
-               if(codec->modem)
-               {
-                       printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", ac97_id);
-                       ac97_release_codec(codec);
-                       continue;
-               }
-               
-               card->ac97_features = eid;
-
-               /* Now check the codec for useful features to make up for
-                  the dumbness of the 810 hardware engine */
-
-               if(!(eid&0x0001))
-                       printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n");
-               else
-               {
-                       if(!i810_ac97_enable_variable_rate(codec)) {
-                               printk(KERN_WARNING "i810_audio: Codec refused to allow VRA, using 48Khz only.\n");
-                               card->ac97_features&=~1;
-                       }                       
-               }
-               
-               /* Turn on the amplifier */
-
-               codec->codec_write(codec, AC97_POWER_CONTROL, 
-                        codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000);
-                               
-               /* Determine how many channels the codec(s) support   */
-               /*   - The primary codec always supports 2            */
-               /*   - If the codec supports AMAP, surround DACs will */
-               /*     automaticlly get assigned to slots.            */
-               /*     * Check for surround DACs and increment if     */
-               /*       found.                                       */
-               /*   - Else check if the codec is revision 2.2        */
-               /*     * If surround DACs exist, assign them to slots */
-               /*       and increment channel count.                 */
-
-               /* All of this only applies to ICH2 and above. ICH    */
-               /* and ICH0 only support 2 channels.  ICH2 will only  */
-               /* support multiple codecs in a "split audio" config. */
-               /* as described above.                                */
-
-               /* TODO: Remove all the debugging messages!           */
-
-               if((eid & 0xc000) == 0) /* primary codec */
-                       total_channels += 2; 
-
-               if(eid & 0x200) { /* GOOD, AMAP support */
-                       if (eid & 0x0080) /* L/R Surround channels */
-                               total_channels += 2;
-                       if (eid & 0x0140) /* LFE and Center channels */
-                               total_channels += 2;
-                       printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", ac97_id, total_channels);
-               } else if (eid & 0x0400) {  /* this only works on 2.2 compliant codecs */
-                       eid &= 0xffcf;
-                       if((eid & 0xc000) != 0) {
-                               switch ( total_channels ) {
-                                       case 2:
-                                               /* Set dsa1, dsa0 to 01 */
-                                               eid |= 0x0010;
-                                               break;
-                                       case 4:
-                                               /* Set dsa1, dsa0 to 10 */
-                                               eid |= 0x0020;
-                                               break;
-                                       case 6:
-                                               /* Set dsa1, dsa0 to 11 */
-                                               eid |= 0x0030;
-                                               break;
-                               }
-                               total_channels += 2;
-                       }
-                       i810_ac97_set(codec, AC97_EXTENDED_ID, eid);
-                       eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-                       printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", ac97_id, eid);
-                       if (eid & 0x0080) /* L/R Surround channels */
-                               total_channels += 2;
-                       if (eid & 0x0140) /* LFE and Center channels */
-                               total_channels += 2;
-                       printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", ac97_id, total_channels);
-               } else {
-                       printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", ac97_id, total_channels);
-               }
-
-               if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
-                       printk(KERN_ERR "i810_audio: couldn't register mixer!\n");
-                       ac97_release_codec(codec);
-                       break;
-               }
-
-               card->ac97_codec[num_ac97] = codec;
-       }
-
-       /* tune up the primary codec */
-       ac97_tune_hardware(card->pci_dev, ac97_quirks, ac97_quirk);
-
-       /* pick the minimum of channels supported by ICHx or codec(s) */
-       card->channels = (card->channels > total_channels)?total_channels:card->channels;
-
-       return num_ac97;
-}
-
-static void __devinit i810_configure_clocking (void)
-{
-       struct i810_card *card;
-       struct i810_state *state;
-       struct dmabuf *dmabuf;
-       unsigned int i, offset, new_offset;
-       unsigned long flags;
-
-       card = devs;
-       /* We could try to set the clocking for multiple cards, but can you even have
-        * more than one i810 in a machine?  Besides, clocking is global, so unless
-        * someone actually thinks more than one i810 in a machine is possible and
-        * decides to rewrite that little bit, setting the rate for more than one card
-        * is a waste of time.
-        */
-       if(card != NULL) {
-               state = card->states[0] = (struct i810_state *)
-                                       kzalloc(sizeof(struct i810_state), GFP_KERNEL);
-               if (state == NULL)
-                       return;
-               dmabuf = &state->dmabuf;
-
-               dmabuf->write_channel = card->alloc_pcm_channel(card);
-               state->virt = 0;
-               state->card = card;
-               state->magic = I810_STATE_MAGIC;
-               init_waitqueue_head(&dmabuf->wait);
-               mutex_init(&state->open_mutex);
-               dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
-               dmabuf->trigger = PCM_ENABLE_OUTPUT;
-               i810_set_spdif_output(state, -1, 0);
-               i810_set_dac_channels(state, 2);
-               i810_set_dac_rate(state, 48000);
-               if(prog_dmabuf(state, 0) != 0) {
-                       goto config_out_nodmabuf;
-               }
-               if(dmabuf->dmasize < 16384) {
-                       goto config_out;
-               }
-               dmabuf->count = dmabuf->dmasize;
-               CIV_TO_LVI(card, dmabuf->write_channel->port, -1);
-               local_irq_save(flags);
-               start_dac(state);
-               offset = i810_get_dma_addr(state, 0);
-               mdelay(50);
-               new_offset = i810_get_dma_addr(state, 0);
-               stop_dac(state);
-               local_irq_restore(flags);
-               i = new_offset - offset;
-#ifdef DEBUG_INTERRUPTS
-               printk("i810_audio: %d bytes in 50 milliseconds\n", i);
-#endif
-               if(i == 0)
-                       goto config_out;
-               i = i / 4 * 20;
-               if (i > 48500 || i < 47500) {
-                       clocking = clocking * clocking / i;
-                       printk("i810_audio: setting clocking to %d\n", clocking);
-               }
-config_out:
-               dealloc_dmabuf(state);
-config_out_nodmabuf:
-               state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num);
-               kfree(state);
-               card->states[0] = NULL;
-       }
-}
-
-/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
-   until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
-   
-static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
-       struct i810_card *card;
-
-       if (pci_enable_device(pci_dev))
-               return -EIO;
-
-       if (pci_set_dma_mask(pci_dev, I810_DMA_MASK)) {
-               printk(KERN_ERR "i810_audio: architecture does not support"
-                      " 32bit PCI busmaster DMA\n");
-               return -ENODEV;
-       }
-       
-       if ((card = kzalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) {
-               printk(KERN_ERR "i810_audio: out of memory\n");
-               return -ENOMEM;
-       }
-
-       card->initializing = 1;
-       card->pci_dev = pci_dev;
-       card->pci_id = pci_id->device;
-       card->ac97base = pci_resource_start (pci_dev, 0);
-       card->iobase = pci_resource_start (pci_dev, 1);
-
-       if (!(card->ac97base) || !(card->iobase)) {
-               card->ac97base = 0;
-               card->iobase = 0;
-       }
-
-       /* if chipset could have mmio capability, check it */ 
-       if (card_cap[pci_id->driver_data].flags & CAP_MMIO) {
-               card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2);
-               card->iobase_mmio_phys = pci_resource_start (pci_dev, 3);
-
-               if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) {
-                       card->use_mmio = 1;
-               }
-               else {
-                       card->ac97base_mmio_phys = 0;
-                       card->iobase_mmio_phys = 0;
-               }
-       }
-
-       if (!(card->use_mmio) && (!(card->iobase) || !(card->ac97base))) {
-               printk(KERN_ERR "i810_audio: No I/O resources available.\n");
-               goto out_mem;
-       }
-
-       card->irq = pci_dev->irq;
-       card->next = devs;
-       card->magic = I810_CARD_MAGIC;
-#ifdef CONFIG_PM
-       card->pm_suspended=0;
-#endif
-       spin_lock_init(&card->lock);
-       spin_lock_init(&card->ac97_lock);
-       devs = card;
-
-       pci_set_master(pci_dev);
-
-       printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, "
-              "MEM 0x%04lx and 0x%04lx, IRQ %d\n",
-              card_names[pci_id->driver_data], 
-              card->iobase, card->ac97base, 
-              card->ac97base_mmio_phys, card->iobase_mmio_phys,
-              card->irq);
-
-       card->alloc_pcm_channel = i810_alloc_pcm_channel;
-       card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;
-       card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel;
-       card->free_pcm_channel = i810_free_pcm_channel;
-
-       if ((card->channel = pci_alloc_consistent(pci_dev,
-           sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) {
-               printk(KERN_ERR "i810: cannot allocate channel DMA memory\n");
-               goto out_mem;
-       }
-
-       { /* We may dispose of this altogether some time soon, so... */
-               struct i810_channel *cp = card->channel;
-
-               cp[0].offset = 0;
-               cp[0].port = 0x00;
-               cp[0].num = 0;
-               cp[1].offset = 0;
-               cp[1].port = 0x10;
-               cp[1].num = 1;
-               cp[2].offset = 0;
-               cp[2].port = 0x20;
-               cp[2].num = 2;
-       }
-
-       /* claim our iospace and irq */
-       if (!request_region(card->iobase, 64, card_names[pci_id->driver_data])) {
-               printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->iobase);
-               goto out_region1;
-       }
-       if (!request_region(card->ac97base, 256, card_names[pci_id->driver_data])) {
-               printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->ac97base);
-               goto out_region2;
-       }
-
-       if (card->use_mmio) {
-               if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
-                       if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
-                               if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) {
-                                       if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) {
-                                               printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n",
-                                                      card_names[pci_id->driver_data], 
-                                                      (unsigned long) card->ac97base_mmio, 
-                                                      (unsigned long) card->iobase_mmio); 
-                                       }
-                                       else {
-                                               iounmap(card->ac97base_mmio);
-                                               release_mem_region(card->ac97base_mmio_phys, 512);
-                                               release_mem_region(card->iobase_mmio_phys, 512);
-                                               card->use_mmio = 0;
-                                       }
-                               }
-                               else {
-                                       iounmap(card->ac97base_mmio);
-                                       release_mem_region(card->ac97base_mmio_phys, 512);
-                                       card->use_mmio = 0;
-                               }
-                       }
-               }
-               else {
-                       card->use_mmio = 0;
-               }
-       }
-
-       /* initialize AC97 codec and register /dev/mixer */
-       if (i810_ac97_init(card) <= 0)
-               goto out_iospace;
-       pci_set_drvdata(pci_dev, card);
-
-       if(clocking == 0) {
-               clocking = 48000;
-               i810_configure_clocking();
-       }
-
-       /* register /dev/dsp */
-       if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
-               int i;
-               printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
-               for (i = 0; i < NR_AC97; i++)
-               if (card->ac97_codec[i] != NULL) {
-                       unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
-                       ac97_release_codec(card->ac97_codec[i]);
-               }
-               goto out_iospace;
-       }
-
-       if (request_irq(card->irq, &i810_interrupt, IRQF_SHARED,
-                       card_names[pci_id->driver_data], card)) {
-               printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
-               goto out_iospace;
-       }
-
-
-       card->initializing = 0;
-       return 0;
-
-out_iospace:
-       if (card->use_mmio) {
-               iounmap(card->ac97base_mmio);
-               iounmap(card->iobase_mmio);
-               release_mem_region(card->ac97base_mmio_phys, 512);
-               release_mem_region(card->iobase_mmio_phys, 256);
-       }
-       release_region(card->ac97base, 256);
-out_region2:
-       release_region(card->iobase, 64);
-out_region1:
-       pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
-           card->channel, card->chandma);
-out_mem:
-       kfree(card);
-       return -ENODEV;
-}
-
-static void __devexit i810_remove(struct pci_dev *pci_dev)
-{
-       int i;
-       struct i810_card *card = pci_get_drvdata(pci_dev);
-       /* free hardware resources */
-       free_irq(card->irq, devs);
-       release_region(card->iobase, 64);
-       release_region(card->ac97base, 256);
-       pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
-                           card->channel, card->chandma);
-       if (card->use_mmio) {
-               iounmap(card->ac97base_mmio);
-               iounmap(card->iobase_mmio);
-               release_mem_region(card->ac97base_mmio_phys, 512);
-               release_mem_region(card->iobase_mmio_phys, 256);
-       }
-
-       /* unregister audio devices */
-       for (i = 0; i < NR_AC97; i++)
-               if (card->ac97_codec[i] != NULL) {
-                       unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
-                       ac97_release_codec(card->ac97_codec[i]);
-                       card->ac97_codec[i] = NULL;
-               }
-       unregister_sound_dsp(card->dev_audio);
-       kfree(card);
-}
-
-#ifdef CONFIG_PM
-static int i810_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
-{
-        struct i810_card *card = pci_get_drvdata(dev);
-        struct i810_state *state;
-       unsigned long flags;
-       struct dmabuf *dmabuf;
-       int i,num_ac97;
-#ifdef DEBUG
-       printk("i810_audio: i810_pm_suspend called\n");
-#endif
-       if(!card) return 0;
-       spin_lock_irqsave(&card->lock, flags);
-       card->pm_suspended=1;
-       for(i=0;i<NR_HW_CH;i++) {
-               state = card->states[i];
-               if(!state) continue;
-               /* this happens only if there are open files */
-               dmabuf = &state->dmabuf;
-               if(dmabuf->enable & DAC_RUNNING ||
-                  (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
-                       state->pm_saved_dac_rate=dmabuf->rate;
-                       stop_dac(state);
-               } else {
-                       state->pm_saved_dac_rate=0;
-               }
-               if(dmabuf->enable & ADC_RUNNING) {
-                       state->pm_saved_adc_rate=dmabuf->rate;  
-                       stop_adc(state);
-               } else {
-                       state->pm_saved_adc_rate=0;
-               }
-               dmabuf->ready = 0;
-               dmabuf->swptr = dmabuf->hwptr = 0;
-               dmabuf->count = dmabuf->total_bytes = 0;
-       }
-
-       spin_unlock_irqrestore(&card->lock, flags);
-
-       /* save mixer settings */
-       for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
-               struct ac97_codec *codec = card->ac97_codec[num_ac97];
-               if(!codec) continue;
-               for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) {
-                       if((supported_mixer(codec,i)) &&
-                          (codec->read_mixer)) {
-                               card->pm_saved_mixer_settings[i][num_ac97]=
-                                       codec->read_mixer(codec,i);
-                       }
-               }
-       }
-       pci_save_state(dev); /* XXX do we need this? */
-       pci_disable_device(dev); /* disable busmastering */
-       pci_set_power_state(dev,3); /* Zzz. */
-
-       return 0;
-}
-
-
-static int i810_pm_resume(struct pci_dev *dev)
-{
-       int num_ac97,i=0;
-       struct i810_card *card=pci_get_drvdata(dev);
-       pci_enable_device(dev);
-       pci_restore_state (dev);
-
-       /* observation of a toshiba portege 3440ct suggests that the 
-          hardware has to be more or less completely reinitialized from
-          scratch after an apm suspend.  Works For Me.   -dan */
-
-       i810_ac97_power_up_bus(card);
-
-       for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
-               struct ac97_codec *codec = card->ac97_codec[num_ac97];
-               /* check they haven't stolen the hardware while we were
-                  away */
-               if(!codec || !i810_ac97_exists(card,num_ac97)) {
-                       if(num_ac97) continue;
-                       else BUG();
-               }
-               if(!i810_ac97_probe_and_powerup(card,codec)) BUG();
-               
-               if((card->ac97_features&0x0001)) {
-                       /* at probe time we found we could do variable
-                          rates, but APM suspend has made it forget
-                          its magical powers */
-                       if(!i810_ac97_enable_variable_rate(codec)) BUG();
-               }
-               /* we lost our mixer settings, so restore them */
-               for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) {
-                       if(supported_mixer(codec,i)){
-                               int val=card->
-                                       pm_saved_mixer_settings[i][num_ac97];
-                               codec->mixer_state[i]=val;
-                               codec->write_mixer(codec,i,
-                                                  (val  & 0xff) ,
-                                                  ((val >> 8)  & 0xff) );
-                       }
-               }
-       }
-
-       /* we need to restore the sample rate from whatever it was */
-       for(i=0;i<NR_HW_CH;i++) {
-               struct i810_state * state=card->states[i];
-               if(state) {
-                       if(state->pm_saved_adc_rate)
-                               i810_set_adc_rate(state,state->pm_saved_adc_rate);
-                       if(state->pm_saved_dac_rate)
-                               i810_set_dac_rate(state,state->pm_saved_dac_rate);
-               }
-       }
-
-       
-        card->pm_suspended = 0;
-
-       /* any processes that were reading/writing during the suspend
-          probably ended up here */
-       for(i=0;i<NR_HW_CH;i++) {
-               struct i810_state *state = card->states[i];
-               if(state) wake_up(&state->dmabuf.wait);
-        }
-
-       return 0;
-}      
-#endif /* CONFIG_PM */
-
-MODULE_AUTHOR("The Linux kernel team");
-MODULE_DESCRIPTION("Intel 810 audio support");
-MODULE_LICENSE("GPL");
-module_param(ftsodell, int, 0444);
-module_param(clocking, uint, 0444);
-module_param(strict_clocking, int, 0444);
-module_param(spdif_locked, int, 0444);
-
-#define I810_MODULE_NAME "i810_audio"
-
-static struct pci_driver i810_pci_driver = {
-       .name           = I810_MODULE_NAME,
-       .id_table       = i810_pci_tbl,
-       .probe          = i810_probe,
-       .remove         = __devexit_p(i810_remove),
-#ifdef CONFIG_PM
-       .suspend        = i810_pm_suspend,
-       .resume         = i810_pm_resume,
-#endif /* CONFIG_PM */
-};
-
-
-static int __init i810_init_module (void)
-{
-       int retval;
-
-       printk(KERN_INFO "Intel 810 + AC97 Audio, version "
-              DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
-
-       retval = pci_register_driver(&i810_pci_driver);
-       if (retval)
-               return retval;
-
-       if(ftsodell != 0) {
-               printk("i810_audio: ftsodell is now a deprecated option.\n");
-       }
-       if(spdif_locked > 0 ) {
-               if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) {
-                       printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked);
-               } else {
-                       printk("i810_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
-                       spdif_locked = 0;
-               }
-       }
-       
-       return 0;
-}
-
-static void __exit i810_cleanup_module (void)
-{
-       pci_unregister_driver(&i810_pci_driver);
-}
-
-module_init(i810_init_module);
-module_exit(i810_cleanup_module);
-
-/*
-Local Variables:
-c-basic-offset: 8
-End:
-*/
index ece428b2ba9fef34319670b25039bf5783c5bfe6..16ed06950dc1b5c363d4740009b0d1bc5fa3c194 100644 (file)
@@ -232,14 +232,12 @@ static int set_irq(pss_confdata * devc, int dev, int irq)
        return 1;
 }
 
-static int set_io_base(pss_confdata * devc, int dev, int base)
+static void set_io_base(pss_confdata * devc, int dev, int base)
 {
        unsigned short  tmp = inw(REG(dev)) & 0x003f;
        unsigned short  bits = (base & 0x0ffc) << 4;
 
        outw(bits | tmp, REG(dev));
-
-       return 1;
 }
 
 static int set_dma(pss_confdata * devc, int dev, int dma)
@@ -673,20 +671,12 @@ static void configure_nonsound_components(void)
 
        /* Configure CDROM port */
 
-       if(pss_cdrom_port == -1)        /* If cdrom port enablation wasn't requested */
-       {
+       if (pss_cdrom_port == -1) {     /* If cdrom port enablation wasn't requested */
                printk(KERN_INFO "PSS: CDROM port not enabled.\n");
-       }
-       else if(check_region(pss_cdrom_port, 2))
-       {
+       } else if (check_region(pss_cdrom_port, 2)) {
                printk(KERN_ERR "PSS: CDROM I/O port conflict.\n");
-       }
-       else if(!set_io_base(devc, CONF_CDROM, pss_cdrom_port))
-       {
-               printk(KERN_ERR "PSS: CDROM I/O port could not be set.\n");
-       }
-       else                                    /* CDROM port successfully configured */
-       {
+       } else {
+               set_io_base(devc, CONF_CDROM, pss_cdrom_port);
                printk(KERN_INFO "PSS: CDROM I/O port set to 0x%x.\n", pss_cdrom_port);
        }
 }
@@ -758,10 +748,7 @@ static int __init probe_pss_mpu(struct address_info *hw_config)
                printk(KERN_ERR "PSS: MPU I/O port conflict\n");
                return 0;
        }
-       if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) {
-               printk(KERN_ERR "PSS: MIDI base could not be set.\n");
-               goto fail;
-       }
+       set_io_base(devc, CONF_MIDI, hw_config->io_base);
        if (!set_irq(devc, CONF_MIDI, hw_config->irq)) {
                printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n");
                goto fail;
@@ -1057,10 +1044,7 @@ static int __init probe_pss_mss(struct address_info *hw_config)
                release_region(hw_config->io_base, 4);
                return 0;
        }
-       if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) {
-               printk("PSS: WSS base not settable.\n");
-               goto fail;
-       }
+       set_io_base(devc, CONF_WSS, hw_config->io_base);
        if (!set_irq(devc, CONF_WSS, hw_config->irq)) {
                printk("PSS: WSS IRQ allocation error.\n");
                goto fail;
index 07cbacf63824602d3a2763984efc3368c5c0f4ad..77d0e5efda76a9bcd2138f878b2e0a442f137137 100644 (file)
@@ -1228,7 +1228,8 @@ int probe_sbmpu(struct address_info *hw_config, struct module *owner)
                }
                attach_mpu401(hw_config, owner);
                if (last_sb->irq == -hw_config->irq)
-                       last_sb->midi_irq_cookie=(void *)hw_config->slots[1];
+                       last_sb->midi_irq_cookie =
+                               (void *)(long) hw_config->slots[1];
                return 1;
        }
 #endif
index 96adc47917aa538b57c60ac67ef7f11fe6deb881..6959ee1bd17f46cf41965fb295361c410370fd13 100644 (file)
@@ -2935,7 +2935,7 @@ trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
        do {
                if ((inw(TRID_REG(card, address)) & busy) == 0)
                        break;
-       } while (count--);
+       } while (--count);
 
        data |= (mask | (reg & AC97_REG_ADDR));
 
@@ -2996,7 +2996,7 @@ trident_ac97_get(struct ac97_codec *codec, u8 reg)
                data = inl(TRID_REG(card, address));
                if ((data & busy) == 0)
                        break;
-       } while (count--);
+       } while (--count);
        spin_unlock_irqrestore(&card->lock, flags);
 
        if (count == 0) {
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
deleted file mode 100644 (file)
index f95aa09..0000000
+++ /dev/null
@@ -1,3616 +0,0 @@
-/*
- * Support for VIA 82Cxxx Audio Codecs
- * Copyright 1999,2000 Jeff Garzik
- *
- * Updated to support the VIA 8233/8235 audio subsystem
- * Alan Cox <alan@redhat.com> (C) Copyright 2002, 2003 Red Hat Inc
- *
- * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
- * See the "COPYING" file distributed with this software for more info.
- * NO WARRANTY
- *
- * For a list of known bugs (errata) and documentation,
- * see via-audio.pdf in Documentation/DocBook.
- * If this documentation does not exist, run "make pdfdocs".
- */
-
-
-#define VIA_VERSION    "1.9.1-ac4-2.5"
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/poison.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/sound.h>
-#include <linux/poll.h>
-#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/mutex.h>
-
-#include "sound_config.h"
-#include "dev_table.h"
-#include "mpu401.h"
-
-
-#undef VIA_DEBUG       /* define to enable debugging output and checks */
-#ifdef VIA_DEBUG
-/* note: prints function name for you */
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#undef VIA_NDEBUG      /* define to disable lightweight runtime checks */
-#ifdef VIA_NDEBUG
-#define assert(expr)
-#else
-#define assert(expr) \
-        if(!(expr)) {                                  \
-        printk( "Assertion failed! %s,%s,%s,line=%d\n",        \
-        #expr,__FILE__,__FUNCTION__,__LINE__);         \
-        }
-#endif
-
-#define VIA_SUPPORT_MMAP 1 /* buggy, for now... */
-
-#define MAX_CARDS      1
-
-#define VIA_CARD_NAME  "VIA 82Cxxx Audio driver " VIA_VERSION
-#define VIA_MODULE_NAME "via82cxxx"
-#define PFX            VIA_MODULE_NAME ": "
-
-#define VIA_COUNTER_LIMIT      100000
-
-/* size of DMA buffers */
-#define VIA_MAX_BUFFER_DMA_PAGES       32
-
-/* buffering default values in ms */
-#define VIA_DEFAULT_FRAG_TIME          20
-#define VIA_DEFAULT_BUFFER_TIME                500
-
-/* the hardware has a 256 fragment limit */
-#define VIA_MIN_FRAG_NUMBER            2
-#define VIA_MAX_FRAG_NUMBER            128
-
-#define VIA_MAX_FRAG_SIZE              PAGE_SIZE
-#define VIA_MIN_FRAG_SIZE              (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE / VIA_MAX_FRAG_NUMBER)
-
-
-/* 82C686 function 5 (audio codec) PCI configuration registers */
-#define VIA_ACLINK_STATUS      0x40
-#define VIA_ACLINK_CTRL                0x41
-#define VIA_FUNC_ENABLE                0x42
-#define VIA_PNP_CONTROL                0x43
-#define VIA_FM_NMI_CTRL                0x48
-
-/*
- * controller base 0 (scatter-gather) registers
- *
- * NOTE: Via datasheet lists first channel as "read"
- * channel and second channel as "write" channel.
- * I changed the naming of the constants to be more
- * clear than I felt the datasheet to be.
- */
-
-#define VIA_BASE0_PCM_OUT_CHAN 0x00 /* output PCM to user */
-#define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00
-#define VIA_BASE0_PCM_OUT_CHAN_CTRL    0x01
-#define VIA_BASE0_PCM_OUT_CHAN_TYPE    0x02
-
-#define VIA_BASE0_PCM_IN_CHAN          0x10 /* input PCM from user */
-#define VIA_BASE0_PCM_IN_CHAN_STATUS   0x10
-#define VIA_BASE0_PCM_IN_CHAN_CTRL     0x11
-#define VIA_BASE0_PCM_IN_CHAN_TYPE     0x12
-
-/* offsets from base */
-#define VIA_PCM_STATUS                 0x00
-#define VIA_PCM_CONTROL                        0x01
-#define VIA_PCM_TYPE                   0x02
-#define VIA_PCM_LEFTVOL                        0x02
-#define VIA_PCM_RIGHTVOL               0x03
-#define VIA_PCM_TABLE_ADDR             0x04
-#define VIA_PCM_STOPRATE               0x08    /* 8233+ */
-#define VIA_PCM_BLOCK_COUNT            0x0C
-
-/* XXX unused DMA channel for FM PCM data */
-#define VIA_BASE0_FM_OUT_CHAN          0x20
-#define VIA_BASE0_FM_OUT_CHAN_STATUS   0x20
-#define VIA_BASE0_FM_OUT_CHAN_CTRL     0x21
-#define VIA_BASE0_FM_OUT_CHAN_TYPE     0x22
-
-/* Six channel audio output on 8233 */
-#define VIA_BASE0_MULTI_OUT_CHAN               0x40
-#define VIA_BASE0_MULTI_OUT_CHAN_STATUS                0x40
-#define VIA_BASE0_MULTI_OUT_CHAN_CTRL          0x41
-#define VIA_BASE0_MULTI_OUT_CHAN_TYPE          0x42
-
-#define VIA_BASE0_AC97_CTRL            0x80
-#define VIA_BASE0_SGD_STATUS_SHADOW    0x84
-#define VIA_BASE0_GPI_INT_ENABLE       0x8C
-#define VIA_INTR_OUT                   ((1<<0) |  (1<<4) |  (1<<8))
-#define VIA_INTR_IN                    ((1<<1) |  (1<<5) |  (1<<9))
-#define VIA_INTR_FM                    ((1<<2) |  (1<<6) | (1<<10))
-#define VIA_INTR_MASK          (VIA_INTR_OUT | VIA_INTR_IN | VIA_INTR_FM)
-
-/* Newer VIA we need to monitor the low 3 bits of each channel. This
-   mask covers the channels we don't yet use as well 
- */
-#define VIA_NEW_INTR_MASK              0x77077777UL
-
-/* VIA_BASE0_AUDIO_xxx_CHAN_TYPE bits */
-#define VIA_IRQ_ON_FLAG                        (1<<0)  /* int on each flagged scatter block */
-#define VIA_IRQ_ON_EOL                 (1<<1)  /* int at end of scatter list */
-#define VIA_INT_SEL_PCI_LAST_LINE_READ (0)     /* int at PCI read of last line */
-#define VIA_INT_SEL_LAST_SAMPLE_SENT   (1<<2)  /* int at last sample sent */
-#define VIA_INT_SEL_ONE_LINE_LEFT      (1<<3)  /* int at less than one line to send */
-#define VIA_PCM_FMT_STEREO             (1<<4)  /* PCM stereo format (bit clear == mono) */
-#define VIA_PCM_FMT_16BIT              (1<<5)  /* PCM 16-bit format (bit clear == 8-bit) */
-#define VIA_PCM_REC_FIFO               (1<<6)  /* PCM Recording FIFO */
-#define VIA_RESTART_SGD_ON_EOL         (1<<7)  /* restart scatter-gather at EOL */
-#define VIA_PCM_FMT_MASK               (VIA_PCM_FMT_STEREO|VIA_PCM_FMT_16BIT)
-#define VIA_CHAN_TYPE_MASK             (VIA_RESTART_SGD_ON_EOL | \
-                                        VIA_IRQ_ON_FLAG | \
-                                        VIA_IRQ_ON_EOL)
-#define VIA_CHAN_TYPE_INT_SELECT       (VIA_INT_SEL_LAST_SAMPLE_SENT)
-
-/* PCI configuration register bits and masks */
-#define VIA_CR40_AC97_READY    0x01
-#define VIA_CR40_AC97_LOW_POWER        0x02
-#define VIA_CR40_SECONDARY_READY 0x04
-
-#define VIA_CR41_AC97_ENABLE   0x80 /* enable AC97 codec */
-#define VIA_CR41_AC97_RESET    0x40 /* clear bit to reset AC97 */
-#define VIA_CR41_AC97_WAKEUP   0x20 /* wake up from power-down mode */
-#define VIA_CR41_AC97_SDO      0x10 /* force Serial Data Out (SDO) high */
-#define VIA_CR41_VRA           0x08 /* enable variable sample rate */
-#define VIA_CR41_PCM_ENABLE    0x04 /* AC Link SGD Read Channel PCM Data Output */
-#define VIA_CR41_FM_PCM_ENABLE 0x02 /* AC Link FM Channel PCM Data Out */
-#define VIA_CR41_SB_PCM_ENABLE 0x01 /* AC Link SB PCM Data Output */
-#define VIA_CR41_BOOT_MASK     (VIA_CR41_AC97_ENABLE | \
-                                VIA_CR41_AC97_WAKEUP | \
-                                VIA_CR41_AC97_SDO)
-#define VIA_CR41_RUN_MASK      (VIA_CR41_AC97_ENABLE | \
-                                VIA_CR41_AC97_RESET | \
-                                VIA_CR41_VRA | \
-                                VIA_CR41_PCM_ENABLE)
-
-#define VIA_CR42_SB_ENABLE     0x01
-#define VIA_CR42_MIDI_ENABLE   0x02
-#define VIA_CR42_FM_ENABLE     0x04
-#define VIA_CR42_GAME_ENABLE   0x08
-#define VIA_CR42_MIDI_IRQMASK   0x40
-#define VIA_CR42_MIDI_PNP      0x80
-
-#define VIA_CR44_SECOND_CODEC_SUPPORT  (1 << 6)
-#define VIA_CR44_AC_LINK_ACCESS                (1 << 7)
-
-#define VIA_CR48_FM_TRAP_TO_NMI                (1 << 2)
-
-/* controller base 0 register bitmasks */
-#define VIA_INT_DISABLE_MASK           (~(0x01|0x02))
-#define VIA_SGD_STOPPED                        (1 << 2)
-#define VIA_SGD_PAUSED                 (1 << 6)
-#define VIA_SGD_ACTIVE                 (1 << 7)
-#define VIA_SGD_TERMINATE              (1 << 6)
-#define VIA_SGD_FLAG                   (1 << 0)
-#define VIA_SGD_EOL                    (1 << 1)
-#define VIA_SGD_START                  (1 << 7)
-
-#define VIA_CR80_FIRST_CODEC           0
-#define VIA_CR80_SECOND_CODEC          (1 << 30)
-#define VIA_CR80_FIRST_CODEC_VALID     (1 << 25)
-#define VIA_CR80_VALID                 (1 << 25)
-#define VIA_CR80_SECOND_CODEC_VALID    (1 << 27)
-#define VIA_CR80_BUSY                  (1 << 24)
-#define VIA_CR83_BUSY                  (1)
-#define VIA_CR83_FIRST_CODEC_VALID     (1 << 1)
-#define VIA_CR80_READ                  (1 << 23)
-#define VIA_CR80_WRITE_MODE            0
-#define VIA_CR80_REG_IDX(idx)          ((((idx) & 0xFF) >> 1) << 16)
-
-/* capabilities we announce */
-#ifdef VIA_SUPPORT_MMAP
-#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | DSP_CAP_MMAP | \
-                    DSP_CAP_TRIGGER | DSP_CAP_REALTIME)
-#else
-#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | \
-                    DSP_CAP_TRIGGER | DSP_CAP_REALTIME)
-#endif
-
-/* scatter-gather DMA table entry, exactly as passed to hardware */
-struct via_sgd_table {
-       u32 addr;
-       u32 count;      /* includes additional VIA_xxx bits also */
-};
-
-#define VIA_EOL (1 << 31)
-#define VIA_FLAG (1 << 30)
-#define VIA_STOP (1 << 29)
-
-
-enum via_channel_states {
-       sgd_stopped = 0,
-       sgd_in_progress = 1,
-};
-
-
-struct via_buffer_pgtbl {
-       dma_addr_t handle;
-       void *cpuaddr;
-};
-
-
-struct via_channel {
-       atomic_t n_frags;
-       atomic_t hw_ptr;
-       wait_queue_head_t wait;
-
-       unsigned int sw_ptr;
-       unsigned int slop_len;
-       unsigned int n_irqs;
-       int bytes;
-
-       unsigned is_active : 1;
-       unsigned is_record : 1;
-       unsigned is_mapped : 1;
-       unsigned is_enabled : 1;
-       unsigned is_multi: 1;   /* 8233 6 channel */
-       u8 pcm_fmt;             /* VIA_PCM_FMT_xxx */
-       u8 channels;            /* Channel count */
-
-       unsigned rate;          /* sample rate */
-       unsigned int frag_size;
-       unsigned int frag_number;
-       
-       unsigned char intmask;
-
-       volatile struct via_sgd_table *sgtable;
-       dma_addr_t sgt_handle;
-
-       unsigned int page_number;
-       struct via_buffer_pgtbl pgtbl[VIA_MAX_BUFFER_DMA_PAGES];
-
-       long iobase;
-
-       const char *name;
-};
-
-
-/* data stored for each chip */
-struct via_info {
-       struct pci_dev *pdev;
-       long baseaddr;
-
-       struct ac97_codec *ac97;
-       spinlock_t ac97_lock;
-       spinlock_t lock;
-       int card_num;           /* unique card number, from 0 */
-
-       int dev_dsp;            /* /dev/dsp index from register_sound_dsp() */
-
-       unsigned rev_h : 1;
-       unsigned legacy: 1;     /* Has legacy ports */
-       unsigned intmask: 1;    /* Needs int bits */
-       unsigned sixchannel: 1; /* 8233/35 with 6 channel support */
-       unsigned volume: 1;
-
-       unsigned locked_rate : 1;
-       
-       int mixer_vol;          /* 8233/35 volume  - not yet implemented */
-
-       struct mutex syscall_mutex;
-       struct mutex open_mutex;
-
-       /* The 8233/8235 have 4 DX audio channels, two record and
-          one six channel out. We bind ch_in to DX 1, ch_out to multichannel
-          and ch_fm to DX 2. DX 3 and REC0/REC1 are unused at the
-          moment */
-          
-       struct via_channel ch_in;
-       struct via_channel ch_out;
-       struct via_channel ch_fm;
-
-#ifdef CONFIG_MIDI_VIA82CXXX
-        void *midi_devc;
-        struct address_info midi_info;
-#endif
-};
-
-
-/* number of cards, used for assigning unique numbers to cards */
-static unsigned via_num_cards;
-
-
-
-/****************************************************************
- *
- * prototypes
- *
- *
- */
-
-static int via_init_one (struct pci_dev *dev, const struct pci_device_id *id);
-static void __devexit via_remove_one (struct pci_dev *pdev);
-
-static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos);
-static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
-static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait);
-static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int via_dsp_open (struct inode *inode, struct file *file);
-static int via_dsp_release(struct inode *inode, struct file *file);
-static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma);
-
-static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg);
-static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value);
-static u8 via_ac97_wait_idle (struct via_info *card);
-
-static void via_chan_free (struct via_info *card, struct via_channel *chan);
-static void via_chan_clear (struct via_info *card, struct via_channel *chan);
-static void via_chan_pcm_fmt (struct via_channel *chan, int reset);
-static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan);
-
-
-/****************************************************************
- *
- * Various data the driver needs
- *
- *
- */
-
-
-static struct pci_device_id via_pci_tbl[] = {
-       { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-       { 0, }
-};
-MODULE_DEVICE_TABLE(pci,via_pci_tbl);
-
-
-static struct pci_driver via_driver = {
-       .name           = VIA_MODULE_NAME,
-       .id_table       = via_pci_tbl,
-       .probe          = via_init_one,
-       .remove         = __devexit_p(via_remove_one),
-};
-
-
-/****************************************************************
- *
- * Low-level base 0 register read/write helpers
- *
- *
- */
-
-/**
- *     via_chan_stop - Terminate DMA on specified PCM channel
- *     @iobase: PCI base address for SGD channel registers
- *
- *     Terminate scatter-gather DMA operation for given
- *     channel (derived from @iobase), if DMA is active.
- *
- *     Note that @iobase is not the PCI base address,
- *     but the PCI base address plus an offset to
- *     one of three PCM channels supported by the chip.
- *
- */
-
-static inline void via_chan_stop (long iobase)
-{
-       if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE)
-               outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL);
-}
-
-
-/**
- *     via_chan_status_clear - Clear status flags on specified DMA channel
- *     @iobase: PCI base address for SGD channel registers
- *
- *     Clear any pending status flags for the given
- *     DMA channel (derived from @iobase), if any
- *     flags are asserted.
- *
- *     Note that @iobase is not the PCI base address,
- *     but the PCI base address plus an offset to
- *     one of three PCM channels supported by the chip.
- *
- */
-
-static inline void via_chan_status_clear (long iobase)
-{
-       u8 tmp = inb (iobase + VIA_PCM_STATUS);
-
-       if (tmp != 0)
-               outb (tmp, iobase + VIA_PCM_STATUS);
-}
-
-
-/**
- *     sg_begin - Begin recording or playback on a PCM channel
- *     @chan: Channel for which DMA operation shall begin
- *
- *     Start scatter-gather DMA for the given channel.
- *
- */
-
-static inline void sg_begin (struct via_channel *chan)
-{
-       DPRINTK("Start with intmask %d\n", chan->intmask);
-       DPRINTK("About to start from %d to %d\n", 
-               inl(chan->iobase + VIA_PCM_BLOCK_COUNT),
-               inb(chan->iobase + VIA_PCM_STOPRATE + 3));
-       outb (VIA_SGD_START|chan->intmask, chan->iobase + VIA_PCM_CONTROL);
-       DPRINTK("Status is now %02X\n", inb(chan->iobase + VIA_PCM_STATUS));
-       DPRINTK("Control is now %02X\n", inb(chan->iobase + VIA_PCM_CONTROL));
-}
-
-
-static int sg_active (long iobase)
-{
-       u8 tmp = inb (iobase + VIA_PCM_STATUS);
-       if ((tmp & VIA_SGD_STOPPED) || (tmp & VIA_SGD_PAUSED)) {
-               printk(KERN_WARNING "via82cxxx warning: SG stopped or paused\n");
-               return 0;
-       }
-       if (tmp & VIA_SGD_ACTIVE)
-               return 1;
-       return 0;
-}
-
-static int via_sg_offset(struct via_channel *chan)
-{
-       return inl (chan->iobase + VIA_PCM_BLOCK_COUNT) & 0x00FFFFFF;
-}
-
-/****************************************************************
- *
- * Miscellaneous debris
- *
- *
- */
-
-
-/**
- *     via_syscall_down - down the card-specific syscell semaphore
- *     @card: Private info for specified board
- *     @nonblock: boolean, non-zero if O_NONBLOCK is set
- *
- *     Encapsulates standard method of acquiring the syscall sem.
- *
- *     Returns negative errno on error, or zero for success.
- */
-
-static inline int via_syscall_down (struct via_info *card, int nonblock)
-{
-       /* Thomas Sailer:
-        * EAGAIN is supposed to be used if IO is pending,
-        * not if there is contention on some internal
-        * synchronization primitive which should be
-        * held only for a short time anyway
-        */
-       nonblock = 0;
-
-       if (nonblock) {
-               if (!mutex_trylock(&card->syscall_mutex))
-                       return -EAGAIN;
-       } else {
-               if (mutex_lock_interruptible(&card->syscall_mutex))
-                       return -ERESTARTSYS;
-       }
-
-       return 0;
-}
-
-
-/**
- *     via_stop_everything - Stop all audio operations
- *     @card: Private info for specified board
- *
- *     Stops all DMA operations and interrupts, and clear
- *     any pending status bits resulting from those operations.
- */
-
-static void via_stop_everything (struct via_info *card)
-{
-       u8 tmp, new_tmp;
-
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-
-       /*
-        * terminate any existing operations on audio read/write channels
-        */
-       via_chan_stop (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
-       via_chan_stop (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
-       via_chan_stop (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
-       if(card->sixchannel)
-               via_chan_stop (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
-
-       /*
-        * clear any existing stops / flags (sanity check mainly)
-        */
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
-       if(card->sixchannel)
-               via_chan_status_clear (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
-
-       /*
-        * clear any enabled interrupt bits
-        */
-       tmp = inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
-       new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
-       if (tmp != new_tmp)
-               outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
-
-       tmp = inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
-       new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
-       if (tmp != new_tmp)
-               outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
-
-       tmp = inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
-       new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
-       if (tmp != new_tmp)
-               outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
-
-       if(card->sixchannel)
-       {
-               tmp = inb (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
-               new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
-               if (tmp != new_tmp)
-                       outb (0, card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
-       }
-
-       udelay(10);
-
-       /*
-        * clear any existing flags
-        */
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-/**
- *     via_set_rate - Set PCM rate for given channel
- *     @ac97: Pointer to generic codec info struct
- *     @chan: Private info for specified channel
- *     @rate: Desired PCM sample rate, in Khz
- *
- *     Sets the PCM sample rate for a channel.
- *
- *     Values for @rate are clamped to a range of 4000 Khz through 48000 Khz,
- *     due to hardware constraints.
- */
-
-static int via_set_rate (struct ac97_codec *ac97,
-                        struct via_channel *chan, unsigned rate)
-{
-       struct via_info *card = ac97->private_data;
-       int rate_reg;
-       u32 dacp;
-       u32 mast_vol, phone_vol, mono_vol, pcm_vol;
-       u32 mute_vol = 0x8000;  /* The mute volume? -- Seems to work! */
-
-       DPRINTK ("ENTER, rate = %d\n", rate);
-
-       if (chan->rate == rate)
-               goto out;
-       if (card->locked_rate) {
-               chan->rate = 48000;
-               goto out;
-       }
-
-       if (rate > 48000)               rate = 48000;
-       if (rate < 4000)                rate = 4000;
-
-       rate_reg = chan->is_record ? AC97_PCM_LR_ADC_RATE :
-                           AC97_PCM_FRONT_DAC_RATE;
-
-       /* Save current state */
-       dacp=via_ac97_read_reg(ac97, AC97_POWER_CONTROL);
-       mast_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_STEREO);
-       mono_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_MONO);
-       phone_vol = via_ac97_read_reg(ac97, AC97_HEADPHONE_VOL);
-       pcm_vol = via_ac97_read_reg(ac97, AC97_PCMOUT_VOL);
-       /* Mute - largely reduces popping */
-       via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mute_vol);
-       via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mute_vol);
-       via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, mute_vol);
-               via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, mute_vol);
-       /* Power down the DAC */
-       via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp|0x0200);
-
-        /* Set new rate */
-       via_ac97_write_reg (ac97, rate_reg, rate);
-
-       /* Power DAC back up */
-       via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp);
-       udelay (200); /* reduces popping */
-
-       /* Restore volumes */
-       via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mast_vol);
-       via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mono_vol);
-       via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, phone_vol);
-       via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, pcm_vol);
-
-       /* the hardware might return a value different than what we
-        * passed to it, so read the rate value back from hardware
-        * to see what we came up with
-        */
-       chan->rate = via_ac97_read_reg (ac97, rate_reg);
-
-       if (chan->rate == 0) {
-               card->locked_rate = 1;
-               chan->rate = 48000;
-               printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
-       }
-
-out:
-       DPRINTK ("EXIT, returning rate %d Hz\n", chan->rate);
-       return chan->rate;
-}
-
-
-/****************************************************************
- *
- * Channel-specific operations
- *
- *
- */
-
-
-/**
- *     via_chan_init_defaults - Initialize a struct via_channel
- *     @card: Private audio chip info
- *     @chan: Channel to be initialized
- *
- *     Zero @chan, and then set all static defaults for the structure.
- */
-
-static void via_chan_init_defaults (struct via_info *card, struct via_channel *chan)
-{
-       memset (chan, 0, sizeof (*chan));
-
-       if(card->intmask)
-               chan->intmask = 0x23;   /* Turn on the IRQ bits */
-               
-       if (chan == &card->ch_out) {
-               chan->name = "PCM-OUT";
-               if(card->sixchannel)
-               {
-                       chan->iobase = card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN;
-                       chan->is_multi = 1;
-                       DPRINTK("Using multichannel for pcm out\n");
-               }
-               else
-                       chan->iobase = card->baseaddr + VIA_BASE0_PCM_OUT_CHAN;
-       } else if (chan == &card->ch_in) {
-               chan->name = "PCM-IN";
-               chan->iobase = card->baseaddr + VIA_BASE0_PCM_IN_CHAN;
-               chan->is_record = 1;
-       } else if (chan == &card->ch_fm) {
-               chan->name = "PCM-OUT-FM";
-               chan->iobase = card->baseaddr + VIA_BASE0_FM_OUT_CHAN;
-       } else {
-               BUG();
-       }
-
-       init_waitqueue_head (&chan->wait);
-
-       chan->pcm_fmt = VIA_PCM_FMT_MASK;
-       chan->is_enabled = 1;
-
-       chan->frag_number = 0;
-        chan->frag_size = 0;
-       atomic_set(&chan->n_frags, 0);
-       atomic_set (&chan->hw_ptr, 0);
-}
-
-/**
- *      via_chan_init - Initialize PCM channel
- *      @card: Private audio chip info
- *      @chan: Channel to be initialized
- *
- *      Performs some of the preparations necessary to begin
- *      using a PCM channel.
- *
- *      Currently the preparations consist of
- *      setting the PCM channel to a known state.
- */
-
-
-static void via_chan_init (struct via_info *card, struct via_channel *chan)
-{
-
-        DPRINTK ("ENTER\n");
-
-       /* bzero channel structure, and init members to defaults */
-        via_chan_init_defaults (card, chan);
-
-        /* stop any existing channel output */
-        via_chan_clear (card, chan);
-        via_chan_status_clear (chan->iobase);
-        via_chan_pcm_fmt (chan, 1);
-
-       DPRINTK ("EXIT\n");
-}
-
-/**
- *     via_chan_buffer_init - Initialize PCM channel buffer
- *     @card: Private audio chip info
- *     @chan: Channel to be initialized
- *
- *     Performs some of the preparations necessary to begin
- *     using a PCM channel.
- *
- *     Currently the preparations include allocating the
- *     scatter-gather DMA table and buffers,
- *     and passing the
- *     address of the DMA table to the hardware.
- *
- *     Note that special care is taken when passing the
- *     DMA table address to hardware, because it was found
- *     during driver development that the hardware did not
- *     always "take" the address.
- */
-
-static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan)
-{
-       int page, offset;
-       int i;
-
-       DPRINTK ("ENTER\n");
-
-
-       chan->intmask = 0;
-       if(card->intmask)
-               chan->intmask = 0x23;   /* Turn on the IRQ bits */
-               
-       if (chan->sgtable != NULL) {
-               DPRINTK ("EXIT\n");
-               return 0;
-       }
-
-       /* alloc DMA-able memory for scatter-gather table */
-       chan->sgtable = pci_alloc_consistent (card->pdev,
-               (sizeof (struct via_sgd_table) * chan->frag_number),
-               &chan->sgt_handle);
-       if (!chan->sgtable) {
-               printk (KERN_ERR PFX "DMA table alloc fail, aborting\n");
-               DPRINTK ("EXIT\n");
-               return -ENOMEM;
-       }
-
-       memset ((void*)chan->sgtable, 0,
-               (sizeof (struct via_sgd_table) * chan->frag_number));
-
-       /* alloc DMA-able memory for scatter-gather buffers */
-
-       chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE +
-                           (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0);
-
-       for (i = 0; i < chan->page_number; i++) {
-               chan->pgtbl[i].cpuaddr = pci_alloc_consistent (card->pdev, PAGE_SIZE,
-                                             &chan->pgtbl[i].handle);
-
-               if (!chan->pgtbl[i].cpuaddr) {
-                       chan->page_number = i;
-                       goto err_out_nomem;
-               }
-
-#ifndef VIA_NDEBUG
-                memset (chan->pgtbl[i].cpuaddr, 0xBC, chan->frag_size);
-#endif
-
-#if 1
-                DPRINTK ("dmabuf_pg #%d (h=%lx, v2p=%lx, a=%p)\n",
-                       i, (long)chan->pgtbl[i].handle,
-                       virt_to_phys(chan->pgtbl[i].cpuaddr),
-                       chan->pgtbl[i].cpuaddr);
-#endif
-       }
-
-       for (i = 0; i < chan->frag_number; i++) {
-
-               page = i / (PAGE_SIZE / chan->frag_size);
-               offset = (i % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
-
-               chan->sgtable[i].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
-               chan->sgtable[i].addr = cpu_to_le32 (chan->pgtbl[page].handle + offset);
-
-#if 1
-               DPRINTK ("dmabuf #%d (32(h)=%lx)\n",
-                        i,
-                        (long)chan->sgtable[i].addr);
-#endif
-       }
-
-       /* overwrite the last buffer information */
-       chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
-
-       /* set location of DMA-able scatter-gather info table */
-       DPRINTK ("outl (0x%X, 0x%04lX)\n",
-               chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR);
-
-       via_ac97_wait_idle (card);
-       outl (chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR);
-       udelay (20);
-       via_ac97_wait_idle (card);
-       /* load no rate adaption, stereo 16bit, set up ring slots */
-       if(card->sixchannel)
-       {
-               if(!chan->is_multi)
-               {
-                       outl (0xFFFFF | (0x3 << 20) | (chan->frag_number << 24), chan->iobase + VIA_PCM_STOPRATE);
-                       udelay (20);
-                       via_ac97_wait_idle (card);
-               }
-       }
-
-       DPRINTK ("inl (0x%lX) = %x\n",
-               chan->iobase + VIA_PCM_TABLE_ADDR,
-               inl(chan->iobase + VIA_PCM_TABLE_ADDR));
-
-       DPRINTK ("EXIT\n");
-       return 0;
-
-err_out_nomem:
-       printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n");
-       via_chan_buffer_free (card, chan);
-       DPRINTK ("EXIT\n");
-       return -ENOMEM;
-}
-
-
-/**
- *     via_chan_free - Release a PCM channel
- *     @card: Private audio chip info
- *     @chan: Channel to be released
- *
- *     Performs all the functions necessary to clean up
- *     an initialized channel.
- *
- *     Currently these functions include disabled any
- *     active DMA operations, setting the PCM channel
- *     back to a known state, and releasing any allocated
- *     sound buffers.
- */
-
-static void via_chan_free (struct via_info *card, struct via_channel *chan)
-{
-       DPRINTK ("ENTER\n");
-
-       spin_lock_irq (&card->lock);
-
-       /* stop any existing channel output */
-       via_chan_status_clear (chan->iobase);
-       via_chan_stop (chan->iobase);
-       via_chan_status_clear (chan->iobase);
-
-       spin_unlock_irq (&card->lock);
-
-       synchronize_irq(card->pdev->irq);
-
-       DPRINTK ("EXIT\n");
-}
-
-static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan)
-{
-       int i;
-
-        DPRINTK ("ENTER\n");
-
-       /* zero location of DMA-able scatter-gather info table */
-       via_ac97_wait_idle(card);
-       outl (0, chan->iobase + VIA_PCM_TABLE_ADDR);
-
-       for (i = 0; i < chan->page_number; i++)
-               if (chan->pgtbl[i].cpuaddr) {
-                       pci_free_consistent (card->pdev, PAGE_SIZE,
-                                            chan->pgtbl[i].cpuaddr,
-                                            chan->pgtbl[i].handle);
-                       chan->pgtbl[i].cpuaddr = NULL;
-                       chan->pgtbl[i].handle = 0;
-               }
-
-       chan->page_number = 0;
-
-       if (chan->sgtable) {
-               pci_free_consistent (card->pdev,
-                       (sizeof (struct via_sgd_table) * chan->frag_number),
-                       (void*)chan->sgtable, chan->sgt_handle);
-               chan->sgtable = NULL;
-       }
-
-       DPRINTK ("EXIT\n");
-}
-
-
-/**
- *     via_chan_pcm_fmt - Update PCM channel settings
- *     @chan: Channel to be updated
- *     @reset: Boolean.  If non-zero, channel will be reset
- *             to 8-bit mono mode.
- *
- *     Stores the settings of the current PCM format,
- *     8-bit or 16-bit, and mono/stereo, into the
- *     hardware settings for the specified channel.
- *     If @reset is non-zero, the channel is reset
- *     to 8-bit mono mode.  Otherwise, the channel
- *     is set to the values stored in the channel
- *     information struct @chan.
- */
-
-static void via_chan_pcm_fmt (struct via_channel *chan, int reset)
-{
-       DPRINTK ("ENTER, pcm_fmt=0x%02X, reset=%s\n",
-                chan->pcm_fmt, reset ? "yes" : "no");
-
-       assert (chan != NULL);
-
-       if (reset)
-       {
-               /* reset to 8-bit mono mode */
-               chan->pcm_fmt = 0;
-               chan->channels = 1;
-       }
-
-       /* enable interrupts on FLAG and EOL */
-       chan->pcm_fmt |= VIA_CHAN_TYPE_MASK;
-
-       /* if we are recording, enable recording fifo bit */
-       if (chan->is_record)
-               chan->pcm_fmt |= VIA_PCM_REC_FIFO;
-       /* set interrupt select bits where applicable (PCM in & out channels) */
-       if (!chan->is_record)
-               chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;
-       
-       DPRINTK("SET FMT - %02x %02x\n", chan->intmask , chan->is_multi);
-       
-       if(chan->intmask)
-       {
-               u32 m;
-
-               /*
-                *      Channel 0x4 is up to 6 x 16bit and has to be
-                *      programmed differently 
-                */
-                               
-               if(chan->is_multi)
-               {
-                       u8 c = 0;
-                       
-                       /*
-                        *      Load the type bit for num channels
-                        *      and 8/16bit
-                        */
-                        
-                       if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
-                               c = 1 << 7;
-                       if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
-                               c |= (2<<4);
-                       else
-                               c |= (1<<4);
-                               
-                       outb(c, chan->iobase + VIA_PCM_TYPE);
-                       
-                       /*
-                        *      Set the channel steering
-                        *      Mono
-                        *              Channel 0 to slot 3
-                        *              Channel 0 to slot 4
-                        *      Stereo
-                        *              Channel 0 to slot 3
-                        *              Channel 1 to slot 4
-                        */
-                        
-                       switch(chan->channels)
-                       {
-                               case 1:
-                                       outl(0xFF000000 | (1<<0) | (1<<4) , chan->iobase + VIA_PCM_STOPRATE);
-                                       break;
-                               case 2:
-                                       outl(0xFF000000 | (1<<0) | (2<<4) , chan->iobase + VIA_PCM_STOPRATE);
-                                       break;
-                               case 4:
-                                       outl(0xFF000000 | (1<<0) | (2<<4) | (3<<8) | (4<<12), chan->iobase + VIA_PCM_STOPRATE);
-                                       break;
-                               case 6:
-                                       outl(0xFF000000 | (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20), chan->iobase + VIA_PCM_STOPRATE);
-                                       break;
-                       }                               
-               }
-               else
-               {
-                       /*
-                        *      New style, turn off channel volume
-                        *      control, set bits in the right register
-                        */     
-                       outb(0x0, chan->iobase + VIA_PCM_LEFTVOL);
-                       outb(0x0, chan->iobase + VIA_PCM_RIGHTVOL);
-
-                       m = inl(chan->iobase + VIA_PCM_STOPRATE);
-                       m &= ~(3<<20);
-                       if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
-                               m |= (1 << 20);
-                       if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
-                               m |= (1 << 21);
-                       outl(m, chan->iobase + VIA_PCM_STOPRATE);
-               }               
-       }
-       else
-               outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE);
-
-
-       DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n",
-                chan->pcm_fmt,
-                inb (chan->iobase + VIA_PCM_TYPE));
-}
-
-
-/**
- *     via_chan_clear - Stop DMA channel operation, and reset pointers
- *     @card: the chip to accessed
- *     @chan: Channel to be cleared
- *
- *     Call via_chan_stop to halt DMA operations, and then resets
- *     all software pointers which track DMA operation.
- */
-
-static void via_chan_clear (struct via_info *card, struct via_channel *chan)
-{
-       DPRINTK ("ENTER\n");
-       via_chan_stop (chan->iobase);
-       via_chan_buffer_free(card, chan);
-       chan->is_active = 0;
-       chan->is_mapped = 0;
-       chan->is_enabled = 1;
-       chan->slop_len = 0;
-       chan->sw_ptr = 0;
-       chan->n_irqs = 0;
-       atomic_set (&chan->hw_ptr, 0);
-       DPRINTK ("EXIT\n");
-}
-
-
-/**
- *     via_chan_set_speed - Set PCM sample rate for given channel
- *     @card: Private info for specified board
- *     @chan: Channel whose sample rate will be adjusted
- *     @val: New sample rate, in Khz
- *
- *     Helper function for the %SNDCTL_DSP_SPEED ioctl.  OSS semantics
- *     demand that all audio operations halt (if they are not already
- *     halted) when the %SNDCTL_DSP_SPEED is given.
- *
- *     This function halts all audio operations for the given channel
- *     @chan, and then calls via_set_rate to set the audio hardware
- *     to the new rate.
- */
-
-static int via_chan_set_speed (struct via_info *card,
-                              struct via_channel *chan, int val)
-{
-       DPRINTK ("ENTER, requested rate = %d\n", val);
-
-       via_chan_clear (card, chan);
-
-       val = via_set_rate (card->ac97, chan, val);
-
-       DPRINTK ("EXIT, returning %d\n", val);
-       return val;
-}
-
-
-/**
- *     via_chan_set_fmt - Set PCM sample size for given channel
- *     @card: Private info for specified board
- *     @chan: Channel whose sample size will be adjusted
- *     @val: New sample size, use the %AFMT_xxx constants
- *
- *     Helper function for the %SNDCTL_DSP_SETFMT ioctl.  OSS semantics
- *     demand that all audio operations halt (if they are not already
- *     halted) when the %SNDCTL_DSP_SETFMT is given.
- *
- *     This function halts all audio operations for the given channel
- *     @chan, and then calls via_chan_pcm_fmt to set the audio hardware
- *     to the new sample size, either 8-bit or 16-bit.
- */
-
-static int via_chan_set_fmt (struct via_info *card,
-                            struct via_channel *chan, int val)
-{
-       DPRINTK ("ENTER, val=%s\n",
-                val == AFMT_U8 ? "AFMT_U8" :
-                val == AFMT_S16_LE ? "AFMT_S16_LE" :
-                "unknown");
-
-       via_chan_clear (card, chan);
-
-       assert (val != AFMT_QUERY); /* this case is handled elsewhere */
-
-       switch (val) {
-       case AFMT_S16_LE:
-               if ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) == 0) {
-                       chan->pcm_fmt |= VIA_PCM_FMT_16BIT;
-                       via_chan_pcm_fmt (chan, 0);
-               }
-               break;
-
-       case AFMT_U8:
-               if (chan->pcm_fmt & VIA_PCM_FMT_16BIT) {
-                       chan->pcm_fmt &= ~VIA_PCM_FMT_16BIT;
-                       via_chan_pcm_fmt (chan, 0);
-               }
-               break;
-
-       default:
-               DPRINTK ("unknown AFMT: 0x%X\n", val);
-               val = AFMT_S16_LE;
-       }
-
-       DPRINTK ("EXIT\n");
-       return val;
-}
-
-
-/**
- *     via_chan_set_stereo - Enable or disable stereo for a DMA channel
- *     @card: Private info for specified board
- *     @chan: Channel whose stereo setting will be adjusted
- *     @val: New sample size, use the %AFMT_xxx constants
- *
- *     Helper function for the %SNDCTL_DSP_CHANNELS and %SNDCTL_DSP_STEREO ioctls.  OSS semantics
- *     demand that all audio operations halt (if they are not already
- *     halted) when %SNDCTL_DSP_CHANNELS or SNDCTL_DSP_STEREO is given.
- *
- *     This function halts all audio operations for the given channel
- *     @chan, and then calls via_chan_pcm_fmt to set the audio hardware
- *     to enable or disable stereo.
- */
-
-static int via_chan_set_stereo (struct via_info *card,
-                               struct via_channel *chan, int val)
-{
-       DPRINTK ("ENTER, channels = %d\n", val);
-
-       via_chan_clear (card, chan);
-
-       switch (val) {
-
-       /* mono */
-       case 1:
-               chan->pcm_fmt &= ~VIA_PCM_FMT_STEREO;
-               chan->channels = 1;
-               via_chan_pcm_fmt (chan, 0);
-               break;
-
-       /* stereo */
-       case 2:
-               chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
-               chan->channels = 2;
-               via_chan_pcm_fmt (chan, 0);
-               break;
-
-       case 4:
-       case 6:
-               if(chan->is_multi)
-               {
-                       chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
-                       chan->channels = val;
-                       break;
-               }
-       /* unknown */
-       default:
-               val = -EINVAL;
-               break;
-       }
-
-       DPRINTK ("EXIT, returning %d\n", val);
-       return val;
-}
-
-static int via_chan_set_buffering (struct via_info *card,
-                                struct via_channel *chan, int val)
-{
-       int shift;
-
-        DPRINTK ("ENTER\n");
-
-       /* in both cases the buffer cannot be changed */
-       if (chan->is_active || chan->is_mapped) {
-               DPRINTK ("EXIT\n");
-               return -EINVAL;
-       }
-
-       /* called outside SETFRAGMENT */
-       /* set defaults or do nothing */
-       if (val < 0) {
-
-               if (chan->frag_size && chan->frag_number)
-                       goto out;
-
-               DPRINTK ("\n");
-
-               chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate * chan->channels
-                                  * ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1;
-
-               shift = 0;
-               while (chan->frag_size) {
-                       chan->frag_size >>= 1;
-                       shift++;
-               }
-               chan->frag_size = 1 << shift;
-
-               chan->frag_number = (VIA_DEFAULT_BUFFER_TIME / VIA_DEFAULT_FRAG_TIME);
-
-               DPRINTK ("setting default values %d %d\n", chan->frag_size, chan->frag_number);
-       } else {
-               chan->frag_size = 1 << (val & 0xFFFF);
-               chan->frag_number = (val >> 16) & 0xFFFF;
-
-               DPRINTK ("using user values %d %d\n", chan->frag_size, chan->frag_number);
-       }
-
-       /* quake3 wants frag_number to be a power of two */
-       shift = 0;
-       while (chan->frag_number) {
-               chan->frag_number >>= 1;
-               shift++;
-       }
-       chan->frag_number = 1 << shift;
-
-       if (chan->frag_size > VIA_MAX_FRAG_SIZE)
-               chan->frag_size = VIA_MAX_FRAG_SIZE;
-       else if (chan->frag_size < VIA_MIN_FRAG_SIZE)
-               chan->frag_size = VIA_MIN_FRAG_SIZE;
-
-       if (chan->frag_number < VIA_MIN_FRAG_NUMBER)
-                chan->frag_number = VIA_MIN_FRAG_NUMBER;
-        if (chan->frag_number > VIA_MAX_FRAG_NUMBER)
-               chan->frag_number = VIA_MAX_FRAG_NUMBER;
-
-       if ((chan->frag_number * chan->frag_size) / PAGE_SIZE > VIA_MAX_BUFFER_DMA_PAGES)
-               chan->frag_number = (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE) / chan->frag_size;
-
-out:
-       if (chan->is_record)
-               atomic_set (&chan->n_frags, 0);
-       else
-               atomic_set (&chan->n_frags, chan->frag_number);
-
-       DPRINTK ("EXIT\n");
-
-       return 0;
-}
-
-#ifdef VIA_CHAN_DUMP_BUFS
-/**
- *     via_chan_dump_bufs - Display DMA table contents
- *     @chan: Channel whose DMA table will be displayed
- *
- *     Debugging function which displays the contents of the
- *     scatter-gather DMA table for the given channel @chan.
- */
-
-static void via_chan_dump_bufs (struct via_channel *chan)
-{
-       int i;
-
-       for (i = 0; i < chan->frag_number; i++) {
-               DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n",
-                        i, chan->sgtable[i].addr,
-                        chan->sgtable[i].count & 0x00FFFFFF,
-                        chan->sgtable[i].count & VIA_FLAG ? 1 : 0,
-                        chan->sgtable[i].count & VIA_EOL ? 1 : 0);
-       }
-       DPRINTK ("buf_in_use = %d, nextbuf = %d\n",
-                atomic_read (&chan->buf_in_use),
-                atomic_read (&chan->sw_ptr));
-}
-#endif /* VIA_CHAN_DUMP_BUFS */
-
-
-/**
- *     via_chan_flush_frag - Flush partially-full playback buffer to hardware
- *     @chan: Channel whose DMA table will be flushed
- *
- *     Flushes partially-full playback buffer to hardware.
- */
-
-static void via_chan_flush_frag (struct via_channel *chan)
-{
-       DPRINTK ("ENTER\n");
-
-       assert (chan->slop_len > 0);
-
-       if (chan->sw_ptr == (chan->frag_number - 1))
-               chan->sw_ptr = 0;
-       else
-               chan->sw_ptr++;
-
-       chan->slop_len = 0;
-
-       assert (atomic_read (&chan->n_frags) > 0);
-       atomic_dec (&chan->n_frags);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-
-/**
- *     via_chan_maybe_start - Initiate audio hardware DMA operation
- *     @chan: Channel whose DMA is to be started
- *
- *     Initiate DMA operation, if the DMA engine for the given
- *     channel @chan is not already active.
- */
-
-static inline void via_chan_maybe_start (struct via_channel *chan)
-{
-       assert (chan->is_active == sg_active(chan->iobase));
-
-       DPRINTK ("MAYBE START %s\n", chan->name);
-       if (!chan->is_active && chan->is_enabled) {
-               chan->is_active = 1;
-               sg_begin (chan);
-               DPRINTK ("starting channel %s\n", chan->name);
-       }
-}
-
-
-/****************************************************************
- *
- * Interface to ac97-codec module
- *
- *
- */
-
-/**
- *     via_ac97_wait_idle - Wait until AC97 codec is not busy
- *     @card: Private info for specified board
- *
- *     Sleep until the AC97 codec is no longer busy.
- *     Returns the final value read from the SGD
- *     register being polled.
- */
-
-static u8 via_ac97_wait_idle (struct via_info *card)
-{
-       u8 tmp8;
-       int counter = VIA_COUNTER_LIMIT;
-
-       DPRINTK ("ENTER/EXIT\n");
-
-       assert (card != NULL);
-       assert (card->pdev != NULL);
-
-       do {
-               udelay (15);
-
-               tmp8 = inb (card->baseaddr + 0x83);
-       } while ((tmp8 & VIA_CR83_BUSY) && (counter-- > 0));
-
-       if (tmp8 & VIA_CR83_BUSY)
-               printk (KERN_WARNING PFX "timeout waiting on AC97 codec\n");
-       return tmp8;
-}
-
-
-/**
- *     via_ac97_read_reg - Read AC97 standard register
- *     @codec: Pointer to generic AC97 codec info
- *     @reg: Index of AC97 register to be read
- *
- *     Read the value of a single AC97 codec register,
- *     as defined by the Intel AC97 specification.
- *
- *     Defines the standard AC97 read-register operation
- *     required by the kernel's ac97_codec interface.
- *
- *     Returns the 16-bit value stored in the specified
- *     register.
- */
-
-static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg)
-{
-       unsigned long data;
-       struct via_info *card;
-       int counter;
-
-       DPRINTK ("ENTER\n");
-
-       assert (codec != NULL);
-       assert (codec->private_data != NULL);
-
-       card = codec->private_data;
-       
-       spin_lock(&card->ac97_lock);
-
-       /* Every time we write to register 80 we cause a transaction.
-          The only safe way to clear the valid bit is to write it at
-          the same time as the command */
-       data = (reg << 16) | VIA_CR80_READ | VIA_CR80_VALID;
-
-       outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
-       udelay (20);
-
-       for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
-               udelay (1);
-               if ((((data = inl(card->baseaddr + VIA_BASE0_AC97_CTRL)) &
-                     (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID))
-                       goto out;
-       }
-
-       printk (KERN_WARNING PFX "timeout while reading AC97 codec (0x%lX)\n", data);
-       goto err_out;
-
-out:
-       /* Once the valid bit has become set, we must wait a complete AC97
-          frame before the data has settled. */
-       udelay(25);
-       data = (unsigned long) inl (card->baseaddr + VIA_BASE0_AC97_CTRL);
-
-       outb (0x02, card->baseaddr + 0x83);
-
-       if (((data & 0x007F0000) >> 16) == reg) {
-               DPRINTK ("EXIT, success, data=0x%lx, retval=0x%lx\n",
-                        data, data & 0x0000FFFF);
-               spin_unlock(&card->ac97_lock);
-               return data & 0x0000FFFF;
-       }
-
-       printk (KERN_WARNING "via82cxxx_audio: not our index: reg=0x%x, newreg=0x%lx\n",
-               reg, ((data & 0x007F0000) >> 16));
-
-err_out:
-       spin_unlock(&card->ac97_lock);
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-/**
- *     via_ac97_write_reg - Write AC97 standard register
- *     @codec: Pointer to generic AC97 codec info
- *     @reg: Index of AC97 register to be written
- *     @value: Value to be written to AC97 register
- *
- *     Write the value of a single AC97 codec register,
- *     as defined by the Intel AC97 specification.
- *
- *     Defines the standard AC97 write-register operation
- *     required by the kernel's ac97_codec interface.
- */
-
-static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value)
-{
-       u32 data;
-       struct via_info *card;
-       int counter;
-
-       DPRINTK ("ENTER\n");
-
-       assert (codec != NULL);
-       assert (codec->private_data != NULL);
-
-       card = codec->private_data;
-
-       spin_lock(&card->ac97_lock);
-       
-       data = (reg << 16) + value;
-       outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
-       udelay (10);
-
-       for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
-               if ((inb (card->baseaddr + 0x83) & VIA_CR83_BUSY) == 0)
-                       goto out;
-
-               udelay (15);
-       }
-
-       printk (KERN_WARNING PFX "timeout after AC97 codec write (0x%X, 0x%X)\n", reg, value);
-
-out:
-       spin_unlock(&card->ac97_lock);
-       DPRINTK ("EXIT\n");
-}
-
-
-static int via_mixer_open (struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct via_info *card;
-       struct pci_dev *pdev = NULL;
-       struct pci_driver *drvr;
-
-       DPRINTK ("ENTER\n");
-
-       while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
-               drvr = pci_dev_driver (pdev);
-               if (drvr == &via_driver) {
-                       assert (pci_get_drvdata (pdev) != NULL);
-
-                       card = pci_get_drvdata (pdev);
-                       if (card->ac97->dev_mixer == minor)
-                               goto match;
-               }
-       }
-
-       DPRINTK ("EXIT, returning -ENODEV\n");
-       return -ENODEV;
-
-match:
-       pci_dev_put(pdev);
-       file->private_data = card->ac97;
-
-       DPRINTK ("EXIT, returning 0\n");
-       return nonseekable_open(inode, file);
-}
-
-static int via_mixer_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
-                           unsigned long arg)
-{
-       struct ac97_codec *codec = file->private_data;
-       struct via_info *card;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int rc;
-
-       DPRINTK ("ENTER\n");
-
-       assert (codec != NULL);
-       card = codec->private_data;
-       assert (card != NULL);
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) goto out;
-       
-#if 0
-       /*
-        *      Intercept volume control on 8233 and 8235
-        */
-       if(card->volume)
-       {
-               switch(cmd)
-               {
-                       case SOUND_MIXER_READ_VOLUME:
-                               return card->mixer_vol;
-                       case SOUND_MIXER_WRITE_VOLUME:
-                       {
-                               int v;
-                               if(get_user(v, (int *)arg))
-                               {
-                                       rc = -EFAULT;
-                                       goto out;
-                               }
-                               card->mixer_vol = v;
-                       }
-               }
-       }               
-#endif
-       rc = codec->mixer_ioctl(codec, cmd, arg);
-
-       mutex_unlock(&card->syscall_mutex);
-
-out:
-       DPRINTK ("EXIT, returning %d\n", rc);
-       return rc;
-}
-
-
-static const struct file_operations via_mixer_fops = {
-       .owner          = THIS_MODULE,
-       .open           = via_mixer_open,
-       .llseek         = no_llseek,
-       .ioctl          = via_mixer_ioctl,
-};
-
-
-static int __devinit via_ac97_reset (struct via_info *card)
-{
-       struct pci_dev *pdev = card->pdev;
-       u8 tmp8;
-       u16 tmp16;
-
-       DPRINTK ("ENTER\n");
-
-       assert (pdev != NULL);
-
-#ifndef NDEBUG
-       {
-               u8 r40,r41,r42,r43,r44,r48;
-               pci_read_config_byte (card->pdev, 0x40, &r40);
-               pci_read_config_byte (card->pdev, 0x41, &r41);
-               pci_read_config_byte (card->pdev, 0x42, &r42);
-               pci_read_config_byte (card->pdev, 0x43, &r43);
-               pci_read_config_byte (card->pdev, 0x44, &r44);
-               pci_read_config_byte (card->pdev, 0x48, &r48);
-               DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
-                       r40,r41,r42,r43,r44,r48);
-
-               spin_lock_irq (&card->lock);
-               DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
-                        inb (card->baseaddr + 0x00),
-                        inb (card->baseaddr + 0x01),
-                        inb (card->baseaddr + 0x02),
-                        inl (card->baseaddr + 0x04),
-                        inl (card->baseaddr + 0x0C),
-                        inl (card->baseaddr + 0x80),
-                        inl (card->baseaddr + 0x84));
-               spin_unlock_irq (&card->lock);
-
-       }
-#endif
-
-        /*
-         * Reset AC97 controller: enable, disable, enable,
-         * pausing after each command for good luck.  Only
-        * do this if the codec is not ready, because it causes
-        * loud pops and such due to such a hard codec reset.
-         */
-       pci_read_config_byte (pdev, VIA_ACLINK_STATUS, &tmp8);
-       if ((tmp8 & VIA_CR40_AC97_READY) == 0) {
-               pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
-                                      VIA_CR41_AC97_ENABLE |
-                                      VIA_CR41_AC97_RESET |
-                                      VIA_CR41_AC97_WAKEUP);
-               udelay (100);
-
-               pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0);
-               udelay (100);
-
-               pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
-                                      VIA_CR41_AC97_ENABLE |
-                                      VIA_CR41_PCM_ENABLE |
-                                      VIA_CR41_VRA | VIA_CR41_AC97_RESET);
-               udelay (100);
-       }
-
-       /* Make sure VRA is enabled, in case we didn't do a
-        * complete codec reset, above
-        */
-       pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8);
-       if (((tmp8 & VIA_CR41_VRA) == 0) ||
-           ((tmp8 & VIA_CR41_AC97_ENABLE) == 0) ||
-           ((tmp8 & VIA_CR41_PCM_ENABLE) == 0) ||
-           ((tmp8 & VIA_CR41_AC97_RESET) == 0)) {
-               pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
-                                      VIA_CR41_AC97_ENABLE |
-                                      VIA_CR41_PCM_ENABLE |
-                                      VIA_CR41_VRA | VIA_CR41_AC97_RESET);
-               udelay (100);
-       }
-
-       if(card->legacy)
-       {
-#if 0 /* this breaks on K7M */
-               /* disable legacy stuff */
-               pci_write_config_byte (pdev, 0x42, 0x00);
-               udelay(10);
-#endif
-
-               /* route FM trap to IRQ, disable FM trap */
-               pci_write_config_byte (pdev, 0x48, 0x05);
-               udelay(10);
-       }
-       
-       /* disable all codec GPI interrupts */
-       outl (0, pci_resource_start (pdev, 0) + 0x8C);
-
-       /* WARNING: this line is magic.  Remove this
-        * and things break. */
-       /* enable variable rate */
-       tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
-       if ((tmp16 & 1) == 0)
-               via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-static void via_ac97_codec_wait (struct ac97_codec *codec)
-{
-       assert (codec->private_data != NULL);
-       via_ac97_wait_idle (codec->private_data);
-}
-
-
-static int __devinit via_ac97_init (struct via_info *card)
-{
-       int rc;
-       u16 tmp16;
-
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-
-       card->ac97 = ac97_alloc_codec();
-       if(card->ac97 == NULL)
-               return -ENOMEM;
-               
-       card->ac97->private_data = card;
-       card->ac97->codec_read = via_ac97_read_reg;
-       card->ac97->codec_write = via_ac97_write_reg;
-       card->ac97->codec_wait = via_ac97_codec_wait;
-
-       card->ac97->dev_mixer = register_sound_mixer (&via_mixer_fops, -1);
-       if (card->ac97->dev_mixer < 0) {
-               printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n");
-               DPRINTK ("EXIT, returning -EIO\n");
-               ac97_release_codec(card->ac97);
-               return -EIO;
-       }
-
-       rc = via_ac97_reset (card);
-       if (rc) {
-               printk (KERN_ERR PFX "unable to reset AC97 codec, aborting\n");
-               goto err_out;
-       }
-       
-       mdelay(10);
-       
-       if (ac97_probe_codec (card->ac97) == 0) {
-               printk (KERN_ERR PFX "unable to probe AC97 codec, aborting\n");
-               rc = -EIO;
-               goto err_out;
-       }
-
-       /* enable variable rate */
-       tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
-       via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-
-       /*
-        * If we cannot enable VRA, we have a locked-rate codec.
-        * We try again to enable VRA before assuming so, however.
-        */
-       tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
-       if ((tmp16 & 1) == 0) {
-               via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-               tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
-               if ((tmp16 & 1) == 0) {
-                       card->locked_rate = 1;
-                       printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
-               }
-       }
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-
-err_out:
-       unregister_sound_mixer (card->ac97->dev_mixer);
-       DPRINTK ("EXIT, returning %d\n", rc);
-       ac97_release_codec(card->ac97);
-       return rc;
-}
-
-
-static void via_ac97_cleanup (struct via_info *card)
-{
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-       assert (card->ac97->dev_mixer >= 0);
-
-       unregister_sound_mixer (card->ac97->dev_mixer);
-       ac97_release_codec(card->ac97);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-
-/****************************************************************
- *
- * Interrupt-related code
- *
- */
-
-/**
- *     via_intr_channel - handle an interrupt for a single channel
- *      @card: unused
- *     @chan: handle interrupt for this channel
- *
- *     This is the "meat" of the interrupt handler,
- *     containing the actions taken each time an interrupt
- *     occurs.  All communication and coordination with
- *     userspace takes place here.
- *
- *     Locking: inside card->lock
- */
-
-static void via_intr_channel (struct via_info *card, struct via_channel *chan)
-{
-       u8 status;
-       int n;
-       
-       /* check pertinent bits of status register for action bits */
-       status = inb (chan->iobase) & (VIA_SGD_FLAG | VIA_SGD_EOL | VIA_SGD_STOPPED);
-       if (!status)
-               return;
-
-       /* acknowledge any flagged bits ASAP */
-       outb (status, chan->iobase);
-
-       if (!chan->sgtable) /* XXX: temporary solution */
-               return;
-
-       /* grab current h/w ptr value */
-       n = atomic_read (&chan->hw_ptr);
-
-       /* sanity check: make sure our h/w ptr doesn't have a weird value */
-       assert (n >= 0);
-       assert (n < chan->frag_number);
-
-       
-       /* reset SGD data structure in memory to reflect a full buffer,
-        * and advance the h/w ptr, wrapping around to zero if needed
-        */
-       if (n == (chan->frag_number - 1)) {
-               chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_EOL);
-               atomic_set (&chan->hw_ptr, 0);
-       } else {
-               chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_FLAG);
-               atomic_inc (&chan->hw_ptr);
-       }
-
-       /* accounting crap for SNDCTL_DSP_GETxPTR */
-       chan->n_irqs++;
-       chan->bytes += chan->frag_size;
-       /* FIXME - signed overflow is undefined */
-       if (chan->bytes < 0) /* handle overflow of 31-bit value */
-               chan->bytes = chan->frag_size;
-       /* all following checks only occur when not in mmap(2) mode */
-       if (!chan->is_mapped)
-       {
-               /* If we are recording, then n_frags represents the number
-                * of fragments waiting to be handled by userspace.
-                * If we are playback, then n_frags represents the number
-                * of fragments remaining to be filled by userspace.
-                * We increment here.  If we reach max number of fragments,
-                * this indicates an underrun/overrun.  For this case under OSS,
-                * we stop the record/playback process.
-                */
-               if (atomic_read (&chan->n_frags) < chan->frag_number)
-                       atomic_inc (&chan->n_frags);
-               assert (atomic_read (&chan->n_frags) <= chan->frag_number);
-               if (atomic_read (&chan->n_frags) == chan->frag_number) {
-                       chan->is_active = 0;
-                       via_chan_stop (chan->iobase);
-               }
-       }
-       /* wake up anyone listening to see when interrupts occur */
-       wake_up_all (&chan->wait);
-
-       DPRINTK ("%s intr, status=0x%02X, hwptr=0x%lX, chan->hw_ptr=%d\n",
-                chan->name, status, (long) inl (chan->iobase + 0x04),
-                atomic_read (&chan->hw_ptr));
-
-       DPRINTK ("%s intr, channel n_frags == %d, missed %d\n", chan->name,
-                atomic_read (&chan->n_frags), missed);
-}
-
-
-static irqreturn_t  via_interrupt(int irq, void *dev_id)
-{
-       struct via_info *card = dev_id;
-       u32 status32;
-
-       /* to minimize interrupt sharing costs, we use the SGD status
-        * shadow register to check the status of all inputs and
-        * outputs with a single 32-bit bus read.  If no interrupt
-        * conditions are flagged, we exit immediately
-        */
-       status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);
-       if (!(status32 & VIA_INTR_MASK))
-        {
-#ifdef CONFIG_MIDI_VIA82CXXX
-                if (card->midi_devc)
-                       uart401intr(irq, card->midi_devc);
-#endif
-               return IRQ_HANDLED;
-       }
-       DPRINTK ("intr, status32 == 0x%08X\n", status32);
-
-       /* synchronize interrupt handling under SMP.  this spinlock
-        * goes away completely on UP
-        */
-       spin_lock (&card->lock);
-
-       if (status32 & VIA_INTR_OUT)
-               via_intr_channel (card, &card->ch_out);
-       if (status32 & VIA_INTR_IN)
-               via_intr_channel (card, &card->ch_in);
-       if (status32 & VIA_INTR_FM)
-               via_intr_channel (card, &card->ch_fm);
-
-       spin_unlock (&card->lock);
-       
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t via_new_interrupt(int irq, void *dev_id)
-{
-       struct via_info *card = dev_id;
-       u32 status32;
-
-       /* to minimize interrupt sharing costs, we use the SGD status
-        * shadow register to check the status of all inputs and
-        * outputs with a single 32-bit bus read.  If no interrupt
-        * conditions are flagged, we exit immediately
-        */
-       status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);
-       if (!(status32 & VIA_NEW_INTR_MASK))
-               return IRQ_NONE;
-       /*
-        * goes away completely on UP
-        */
-       spin_lock (&card->lock);
-
-       via_intr_channel (card, &card->ch_out);
-       via_intr_channel (card, &card->ch_in);
-       via_intr_channel (card, &card->ch_fm);
-
-       spin_unlock (&card->lock);
-       return IRQ_HANDLED;
-}
-
-
-/**
- *     via_interrupt_init - Initialize interrupt handling
- *     @card: Private info for specified board
- *
- *     Obtain and reserve IRQ for using in handling audio events.
- *     Also, disable any IRQ-generating resources, to make sure
- *     we don't get interrupts before we want them.
- */
-
-static int via_interrupt_init (struct via_info *card)
-{
-       u8 tmp8;
-
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-       assert (card->pdev != NULL);
-
-       /* check for sane IRQ number. can this ever happen? */
-       if (card->pdev->irq < 2) {
-               printk (KERN_ERR PFX "insane IRQ %d, aborting\n",
-                       card->pdev->irq);
-               DPRINTK ("EXIT, returning -EIO\n");
-               return -EIO;
-       }
-
-       /* VIA requires this is done */
-       pci_write_config_byte(card->pdev, PCI_INTERRUPT_LINE, card->pdev->irq);
-       
-       if(card->legacy)
-       {
-               /* make sure FM irq is not routed to us */
-               pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);
-               if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {
-                       tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;
-                       pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);
-               }
-               if (request_irq (card->pdev->irq, via_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) {
-                       printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
-                               card->pdev->irq);
-                       DPRINTK ("EXIT, returning -EBUSY\n");
-                       return -EBUSY;
-               }
-       }
-       else 
-       {
-               if (request_irq (card->pdev->irq, via_new_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) {
-                       printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
-                               card->pdev->irq);
-                       DPRINTK ("EXIT, returning -EBUSY\n");
-                       return -EBUSY;
-               }
-       }
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-/****************************************************************
- *
- * OSS DSP device
- *
- */
-
-static const struct file_operations via_dsp_fops = {
-       .owner          = THIS_MODULE,
-       .open           = via_dsp_open,
-       .release        = via_dsp_release,
-       .read           = via_dsp_read,
-       .write          = via_dsp_write,
-       .poll           = via_dsp_poll,
-       .llseek         = no_llseek,
-       .ioctl          = via_dsp_ioctl,
-       .mmap           = via_dsp_mmap,
-};
-
-
-static int __devinit via_dsp_init (struct via_info *card)
-{
-       u8 tmp8;
-
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-
-       if(card->legacy)
-       {
-               /* turn off legacy features, if not already */
-               pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8);
-               if (tmp8 & (VIA_CR42_SB_ENABLE |  VIA_CR42_FM_ENABLE)) {
-                       tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE);
-                       pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8);
-               }
-       }
-
-       via_stop_everything (card);
-
-       card->dev_dsp = register_sound_dsp (&via_dsp_fops, -1);
-       if (card->dev_dsp < 0) {
-               DPRINTK ("EXIT, returning -ENODEV\n");
-               return -ENODEV;
-       }
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-static void via_dsp_cleanup (struct via_info *card)
-{
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-       assert (card->dev_dsp >= 0);
-
-       via_stop_everything (card);
-
-       unregister_sound_dsp (card->dev_dsp);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-static struct page * via_mm_nopage (struct vm_area_struct * vma,
-                                   unsigned long address, int *type)
-{
-       struct via_info *card = vma->vm_private_data;
-       struct via_channel *chan = &card->ch_out;
-       unsigned long max_bufs;
-       struct page *dmapage;
-       unsigned long pgoff;
-       int rd, wr;
-
-       DPRINTK ("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n",
-                vma->vm_start,
-                address - vma->vm_start,
-                (address - vma->vm_start) >> PAGE_SHIFT,
-                address);
-
-        if (address > vma->vm_end) {
-               DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
-               return NOPAGE_SIGBUS; /* Disallow mremap */
-       }
-        if (!card) {
-               DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
-               return NOPAGE_SIGBUS;   /* Nothing allocated */
-       }
-
-       pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT);
-       rd = card->ch_in.is_mapped;
-       wr = card->ch_out.is_mapped;
-
-       max_bufs = chan->frag_number;
-       if (rd && wr)
-               max_bufs *= 2;
-       if (pgoff >= max_bufs)
-               return NOPAGE_SIGBUS;
-
-       /* if full-duplex (read+write) and we have two sets of bufs,
-        * then the playback buffers come first, sez soundcard.c */
-       if (pgoff >= chan->page_number) {
-               pgoff -= chan->page_number;
-               chan = &card->ch_in;
-       } else if (!wr)
-               chan = &card->ch_in;
-
-       assert ((((unsigned long)chan->pgtbl[pgoff].cpuaddr) % PAGE_SIZE) == 0);
-
-       dmapage = virt_to_page (chan->pgtbl[pgoff].cpuaddr);
-       DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n",
-                dmapage, (unsigned long) chan->pgtbl[pgoff].cpuaddr);
-       get_page (dmapage);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return dmapage;
-}
-
-
-#ifndef VM_RESERVED
-static int via_mm_swapout (struct page *page, struct file *filp)
-{
-       return 0;
-}
-#endif /* VM_RESERVED */
-
-
-static struct vm_operations_struct via_mm_ops = {
-       .nopage         = via_mm_nopage,
-
-#ifndef VM_RESERVED
-       .swapout        = via_mm_swapout,
-#endif
-};
-
-
-static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct via_info *card;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int rc = -EINVAL, rd=0, wr=0;
-       unsigned long max_size, size, start, offset;
-
-       assert (file != NULL);
-       assert (vma != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       DPRINTK ("ENTER, start %lXh, size %ld, pgoff %ld\n",
-                vma->vm_start,
-                vma->vm_end - vma->vm_start,
-                vma->vm_pgoff);
-
-       max_size = 0;
-       if (vma->vm_flags & VM_READ) {
-               rd = 1;
-               via_chan_set_buffering(card, &card->ch_in, -1);
-               via_chan_buffer_init (card, &card->ch_in);
-               max_size += card->ch_in.page_number << PAGE_SHIFT;
-       }
-       if (vma->vm_flags & VM_WRITE) {
-               wr = 1;
-               via_chan_set_buffering(card, &card->ch_out, -1);
-               via_chan_buffer_init (card, &card->ch_out);
-               max_size += card->ch_out.page_number << PAGE_SHIFT;
-       }
-
-       start = vma->vm_start;
-       offset = (vma->vm_pgoff << PAGE_SHIFT);
-       size = vma->vm_end - vma->vm_start;
-
-       /* some basic size/offset sanity checks */
-       if (size > max_size)
-               goto out;
-       if (offset > max_size - size)
-               goto out;
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) goto out;
-
-       vma->vm_ops = &via_mm_ops;
-       vma->vm_private_data = card;
-
-#ifdef VM_RESERVED
-       vma->vm_flags |= VM_RESERVED;
-#endif
-
-       if (rd)
-               card->ch_in.is_mapped = 1;
-       if (wr)
-               card->ch_out.is_mapped = 1;
-
-       mutex_unlock(&card->syscall_mutex);
-       rc = 0;
-
-out:
-       DPRINTK ("EXIT, returning %d\n", rc);
-       return rc;
-}
-
-
-static ssize_t via_dsp_do_read (struct via_info *card,
-                               char __user *userbuf, size_t count,
-                               int nonblock)
-{
-        DECLARE_WAITQUEUE(wait, current);
-       const char __user *orig_userbuf = userbuf;
-       struct via_channel *chan = &card->ch_in;
-       size_t size;
-       int n, tmp;
-       ssize_t ret = 0;
-
-       /* if SGD has not yet been started, start it */
-       via_chan_maybe_start (chan);
-
-handle_one_block:
-       /* just to be a nice neighbor */
-       /* Thomas Sailer:
-        * But also to ourselves, release semaphore if we do so */
-       if (need_resched()) {
-               mutex_unlock(&card->syscall_mutex);
-               schedule ();
-               ret = via_syscall_down (card, nonblock);
-               if (ret)
-                       goto out;
-       }
-
-       /* grab current channel software pointer.  In the case of
-        * recording, this is pointing to the next buffer that
-        * will receive data from the audio hardware.
-        */
-       n = chan->sw_ptr;
-
-       /* n_frags represents the number of fragments waiting
-        * to be copied to userland.  sleep until at least
-        * one buffer has been read from the audio hardware.
-        */
-       add_wait_queue(&chan->wait, &wait);
-       for (;;) {
-               __set_current_state(TASK_INTERRUPTIBLE);
-               tmp = atomic_read (&chan->n_frags);
-               assert (tmp >= 0);
-               assert (tmp <= chan->frag_number);
-               if (tmp)
-                       break;
-               if (nonblock || !chan->is_active) {
-                       ret = -EAGAIN;
-                       break;
-               }
-
-               mutex_unlock(&card->syscall_mutex);
-
-               DPRINTK ("Sleeping on block %d\n", n);
-               schedule();
-
-               ret = via_syscall_down (card, nonblock);
-               if (ret)
-                       break;
-
-               if (signal_pending (current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&chan->wait, &wait);
-       if (ret)
-               goto out;
-
-       /* Now that we have a buffer we can read from, send
-        * as much as sample data possible to userspace.
-        */
-       while ((count > 0) && (chan->slop_len < chan->frag_size)) {
-               size_t slop_left = chan->frag_size - chan->slop_len;
-               void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr;
-               unsigned ofs = (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
-
-               size = (count < slop_left) ? count : slop_left;
-               if (copy_to_user (userbuf,
-                                 base + ofs + chan->slop_len,
-                                 size)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-
-               count -= size;
-               chan->slop_len += size;
-               userbuf += size;
-       }
-
-       /* If we didn't copy the buffer completely to userspace,
-        * stop now.
-        */
-       if (chan->slop_len < chan->frag_size)
-               goto out;
-
-       /*
-        * If we get to this point, we copied one buffer completely
-        * to userspace, give the buffer back to the hardware.
-        */
-
-       /* advance channel software pointer to point to
-        * the next buffer from which we will copy
-        */
-       if (chan->sw_ptr == (chan->frag_number - 1))
-               chan->sw_ptr = 0;
-       else
-               chan->sw_ptr++;
-
-       /* mark one less buffer waiting to be processed */
-       assert (atomic_read (&chan->n_frags) > 0);
-       atomic_dec (&chan->n_frags);
-
-       /* we are at a block boundary, there is no fragment data */
-       chan->slop_len = 0;
-
-       DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
-               n, chan->sw_ptr, atomic_read (&chan->n_frags));
-
-       DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
-                inb (card->baseaddr + 0x00),
-                inb (card->baseaddr + 0x01),
-                inb (card->baseaddr + 0x02),
-                inl (card->baseaddr + 0x04),
-                inl (card->baseaddr + 0x0C),
-                inl (card->baseaddr + 0x80),
-                inl (card->baseaddr + 0x84));
-
-       if (count > 0)
-               goto handle_one_block;
-
-out:
-       return (userbuf != orig_userbuf) ? (userbuf - orig_userbuf) : ret;
-}
-
-
-static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct via_info *card;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int rc;
-
-       DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",
-                file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) goto out;
-
-       if (card->ch_in.is_mapped) {
-               rc = -ENXIO;
-               goto out_up;
-       }
-
-       via_chan_set_buffering(card, &card->ch_in, -1);
-        rc = via_chan_buffer_init (card, &card->ch_in);
-
-       if (rc)
-               goto out_up;
-
-       rc = via_dsp_do_read (card, buffer, count, nonblock);
-
-out_up:
-       mutex_unlock(&card->syscall_mutex);
-out:
-       DPRINTK ("EXIT, returning %ld\n",(long) rc);
-       return rc;
-}
-
-
-static ssize_t via_dsp_do_write (struct via_info *card,
-                                const char __user *userbuf, size_t count,
-                                int nonblock)
-{
-        DECLARE_WAITQUEUE(wait, current);
-       const char __user *orig_userbuf = userbuf;
-       struct via_channel *chan = &card->ch_out;
-       volatile struct via_sgd_table *sgtable = chan->sgtable;
-       size_t size;
-       int n, tmp;
-       ssize_t ret = 0;
-
-handle_one_block:
-       /* just to be a nice neighbor */
-       /* Thomas Sailer:
-        * But also to ourselves, release semaphore if we do so */
-       if (need_resched()) {
-               mutex_unlock(&card->syscall_mutex);
-               schedule ();
-               ret = via_syscall_down (card, nonblock);
-               if (ret)
-                       goto out;
-       }
-
-       /* grab current channel fragment pointer.  In the case of
-        * playback, this is pointing to the next fragment that
-        * should receive data from userland.
-        */
-       n = chan->sw_ptr;
-
-       /* n_frags represents the number of fragments remaining
-        * to be filled by userspace.  Sleep until
-        * at least one fragment is available for our use.
-        */
-       add_wait_queue(&chan->wait, &wait);
-       for (;;) {
-               __set_current_state(TASK_INTERRUPTIBLE);
-               tmp = atomic_read (&chan->n_frags);
-               assert (tmp >= 0);
-               assert (tmp <= chan->frag_number);
-               if (tmp)
-                       break;
-               if (nonblock || !chan->is_active) {
-                       ret = -EAGAIN;
-                       break;
-               }
-
-               mutex_unlock(&card->syscall_mutex);
-
-               DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);
-               schedule();
-
-               ret = via_syscall_down (card, nonblock);
-               if (ret)
-                       break;
-
-               if (signal_pending (current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&chan->wait, &wait);
-       if (ret)
-               goto out;
-
-       /* Now that we have at least one fragment we can write to, fill the buffer
-        * as much as possible with data from userspace.
-        */
-       while ((count > 0) && (chan->slop_len < chan->frag_size)) {
-               size_t slop_left = chan->frag_size - chan->slop_len;
-
-               size = (count < slop_left) ? count : slop_left;
-               if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len,
-                                   userbuf, size)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-
-               count -= size;
-               chan->slop_len += size;
-               userbuf += size;
-       }
-
-       /* If we didn't fill up the buffer with data, stop now.
-         * Put a 'stop' marker in the DMA table too, to tell the
-         * audio hardware to stop if it gets here.
-         */
-       if (chan->slop_len < chan->frag_size) {
-               sgtable[n].count = cpu_to_le32 (chan->slop_len | VIA_EOL | VIA_STOP);
-               goto out;
-       }
-
-       /*
-         * If we get to this point, we have filled a buffer with
-         * audio data, flush the buffer to audio hardware.
-         */
-
-       /* Record the true size for the audio hardware to notice */
-        if (n == (chan->frag_number - 1))
-                sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
-        else
-                sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
-
-       /* advance channel software pointer to point to
-        * the next buffer we will fill with data
-        */
-       if (chan->sw_ptr == (chan->frag_number - 1))
-               chan->sw_ptr = 0;
-       else
-               chan->sw_ptr++;
-
-       /* mark one less buffer as being available for userspace consumption */
-       assert (atomic_read (&chan->n_frags) > 0);
-       atomic_dec (&chan->n_frags);
-
-       /* we are at a block boundary, there is no fragment data */
-       chan->slop_len = 0;
-
-       /* if SGD has not yet been started, start it */
-       via_chan_maybe_start (chan);
-
-       DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
-               n, chan->sw_ptr, atomic_read (&chan->n_frags));
-
-       DPRINTK ("regs==S=%02X C=%02X TP=%02X BP=%08X RT=%08X SG=%08X CC=%08X SS=%08X\n",
-                inb (card->baseaddr + 0x00),
-                inb (card->baseaddr + 0x01),
-                inb (card->baseaddr + 0x02),
-                inl (card->baseaddr + 0x04),
-                inl (card->baseaddr + 0x08),
-                inl (card->baseaddr + 0x0C),
-                inl (card->baseaddr + 0x80),
-                inl (card->baseaddr + 0x84));
-
-       if (count > 0)
-               goto handle_one_block;
-
-out:
-       if (userbuf - orig_userbuf)
-               return userbuf - orig_userbuf;
-       else
-               return ret;
-}
-
-
-static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct via_info *card;
-       ssize_t rc;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-
-       DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",
-                file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) goto out;
-
-       if (card->ch_out.is_mapped) {
-               rc = -ENXIO;
-               goto out_up;
-       }
-
-       via_chan_set_buffering(card, &card->ch_out, -1);
-       rc = via_chan_buffer_init (card, &card->ch_out);
-
-       if (rc)
-               goto out_up;
-
-       rc = via_dsp_do_write (card, buffer, count, nonblock);
-
-out_up:
-       mutex_unlock(&card->syscall_mutex);
-out:
-       DPRINTK ("EXIT, returning %ld\n",(long) rc);
-       return rc;
-}
-
-
-static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct via_info *card;
-       struct via_channel *chan;
-       unsigned int mask = 0;
-
-       DPRINTK ("ENTER\n");
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       if (file->f_mode & FMODE_READ) {
-               chan = &card->ch_in;
-               if (sg_active (chan->iobase))
-                       poll_wait(file, &chan->wait, wait);
-               if (atomic_read (&chan->n_frags) > 0)
-                       mask |= POLLIN | POLLRDNORM;
-       }
-
-       if (file->f_mode & FMODE_WRITE) {
-               chan = &card->ch_out;
-               if (sg_active (chan->iobase))
-                       poll_wait(file, &chan->wait, wait);
-               if (atomic_read (&chan->n_frags) > 0)
-                       mask |= POLLOUT | POLLWRNORM;
-       }
-
-       DPRINTK ("EXIT, returning %u\n", mask);
-       return mask;
-}
-
-
-/**
- *     via_dsp_drain_playback - sleep until all playback samples are flushed
- *     @card: Private info for specified board
- *     @chan: Channel to drain
- *     @nonblock: boolean, non-zero if O_NONBLOCK is set
- *
- *     Sleeps until all playback has been flushed to the audio
- *     hardware.
- *
- *     Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_drain_playback (struct via_info *card,
-                                  struct via_channel *chan, int nonblock)
-{
-        DECLARE_WAITQUEUE(wait, current);
-       int ret = 0;
-
-       DPRINTK ("ENTER, nonblock = %d\n", nonblock);
-
-       if (chan->slop_len > 0)
-               via_chan_flush_frag (chan);
-
-       if (atomic_read (&chan->n_frags) == chan->frag_number)
-               goto out;
-
-       via_chan_maybe_start (chan);
-
-       add_wait_queue(&chan->wait, &wait);
-       for (;;) {
-               DPRINTK ("FRAGS %d FRAGNUM %d\n", atomic_read(&chan->n_frags), chan->frag_number);
-               __set_current_state(TASK_INTERRUPTIBLE);
-               if (atomic_read (&chan->n_frags) >= chan->frag_number)
-                       break;
-
-               if (nonblock) {
-                       DPRINTK ("EXIT, returning -EAGAIN\n");
-                       ret = -EAGAIN;
-                       break;
-               }
-
-#ifdef VIA_DEBUG
-               {
-               u8 r40,r41,r42,r43,r44,r48;
-               pci_read_config_byte (card->pdev, 0x40, &r40);
-               pci_read_config_byte (card->pdev, 0x41, &r41);
-               pci_read_config_byte (card->pdev, 0x42, &r42);
-               pci_read_config_byte (card->pdev, 0x43, &r43);
-               pci_read_config_byte (card->pdev, 0x44, &r44);
-               pci_read_config_byte (card->pdev, 0x48, &r48);
-               DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
-                       r40,r41,r42,r43,r44,r48);
-
-               DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
-                        inb (card->baseaddr + 0x00),
-                        inb (card->baseaddr + 0x01),
-                        inb (card->baseaddr + 0x02),
-                        inl (card->baseaddr + 0x04),
-                        inl (card->baseaddr + 0x0C),
-                        inl (card->baseaddr + 0x80),
-                        inl (card->baseaddr + 0x84));
-               }
-
-               if (!chan->is_active)
-                       printk (KERN_ERR "sleeping but not active\n");
-#endif
-
-               mutex_unlock(&card->syscall_mutex);
-
-               DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags));
-               schedule();
-
-               if ((ret = via_syscall_down (card, nonblock)))
-                       break;
-
-               if (signal_pending (current)) {
-                       DPRINTK ("EXIT, returning -ERESTARTSYS\n");
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&chan->wait, &wait);
-
-#ifdef VIA_DEBUG
-       {
-               u8 r40,r41,r42,r43,r44,r48;
-               pci_read_config_byte (card->pdev, 0x40, &r40);
-               pci_read_config_byte (card->pdev, 0x41, &r41);
-               pci_read_config_byte (card->pdev, 0x42, &r42);
-               pci_read_config_byte (card->pdev, 0x43, &r43);
-               pci_read_config_byte (card->pdev, 0x44, &r44);
-               pci_read_config_byte (card->pdev, 0x48, &r48);
-               DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
-                       r40,r41,r42,r43,r44,r48);
-
-               DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
-                        inb (card->baseaddr + 0x00),
-                        inb (card->baseaddr + 0x01),
-                        inb (card->baseaddr + 0x02),
-                        inl (card->baseaddr + 0x04),
-                        inl (card->baseaddr + 0x0C),
-                        inl (card->baseaddr + 0x80),
-                        inl (card->baseaddr + 0x84));
-
-               DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_frags));
-       }
-#endif
-
-out:
-       DPRINTK ("EXIT, returning %d\n", ret);
-       return ret;
-}
-
-
-/**
- *     via_dsp_ioctl_space - get information about channel buffering
- *     @card: Private info for specified board
- *     @chan: pointer to channel-specific info
- *     @arg: user buffer for returned information
- *
- *     Handles SNDCTL_DSP_GETISPACE and SNDCTL_DSP_GETOSPACE.
- *
- *     Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_ioctl_space (struct via_info *card,
-                               struct via_channel *chan,
-                               void __user *arg)
-{
-       audio_buf_info info;
-
-       via_chan_set_buffering(card, chan, -1);
-
-       info.fragstotal = chan->frag_number;
-       info.fragsize = chan->frag_size;
-
-       /* number of full fragments we can read/write without blocking */
-       info.fragments = atomic_read (&chan->n_frags);
-
-       if ((chan->slop_len % chan->frag_size > 0) && (info.fragments > 0))
-               info.fragments--;
-
-       /* number of bytes that can be read or written immediately
-        * without blocking.
-        */
-       info.bytes = (info.fragments * chan->frag_size);
-       if (chan->slop_len % chan->frag_size > 0)
-               info.bytes += chan->frag_size - (chan->slop_len % chan->frag_size);
-
-       DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n",
-               info.fragstotal,
-               info.fragsize,
-               info.fragments,
-               info.bytes);
-
-       return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0;
-}
-
-
-/**
- *     via_dsp_ioctl_ptr - get information about hardware buffer ptr
- *     @card: Private info for specified board
- *     @chan: pointer to channel-specific info
- *     @arg: user buffer for returned information
- *
- *     Handles SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR.
- *
- *     Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_ioctl_ptr (struct via_info *card,
-                               struct via_channel *chan,
-                               void __user *arg)
-{
-       count_info info;
-
-       spin_lock_irq (&card->lock);
-
-       info.bytes = chan->bytes;
-       info.blocks = chan->n_irqs;
-       chan->n_irqs = 0;
-
-       spin_unlock_irq (&card->lock);
-
-       if (chan->is_active) {
-               unsigned long extra;
-               info.ptr = atomic_read (&chan->hw_ptr) * chan->frag_size;
-               extra = chan->frag_size - via_sg_offset(chan);
-               info.ptr += extra;
-               info.bytes += extra;
-       } else {
-               info.ptr = 0;
-       }
-
-       DPRINTK ("EXIT, returning bytes=%d, blocks=%d, ptr=%d\n",
-               info.bytes,
-               info.blocks,
-               info.ptr);
-
-       return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0;
-}
-
-
-static int via_dsp_ioctl_trigger (struct via_channel *chan, int val)
-{
-       int enable, do_something;
-
-       if (chan->is_record)
-               enable = (val & PCM_ENABLE_INPUT);
-       else
-               enable = (val & PCM_ENABLE_OUTPUT);
-
-       if (!chan->is_enabled && enable) {
-               do_something = 1;
-       } else if (chan->is_enabled && !enable) {
-               do_something = -1;
-       } else {
-               do_something = 0;
-       }
-
-       DPRINTK ("enable=%d, do_something=%d\n",
-                enable, do_something);
-
-       if (chan->is_active && do_something)
-               return -EINVAL;
-
-       if (do_something == 1) {
-               chan->is_enabled = 1;
-               via_chan_maybe_start (chan);
-               DPRINTK ("Triggering input\n");
-       }
-
-       else if (do_something == -1) {
-               chan->is_enabled = 0;
-               DPRINTK ("Setup input trigger\n");
-       }
-
-       return 0;
-}
-
-
-static int via_dsp_ioctl (struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg)
-{
-       int rc, rd=0, wr=0, val=0;
-       struct via_info *card;
-       struct via_channel *chan;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int __user *ip = (int __user *)arg;
-       void __user *p = (void __user *)arg;
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       if (file->f_mode & FMODE_WRITE)
-               wr = 1;
-       if (file->f_mode & FMODE_READ)
-               rd = 1;
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc)
-               return rc;
-       rc = -EINVAL;
-
-       switch (cmd) {
-
-       /* OSS API version.  XXX unverified */
-       case OSS_GETVERSION:
-               DPRINTK ("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n");
-               rc = put_user (SOUND_VERSION, ip);
-               break;
-
-       /* list of supported PCM data formats */
-       case SNDCTL_DSP_GETFMTS:
-               DPRINTK ("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n");
-                rc = put_user (AFMT_U8 | AFMT_S16_LE, ip);
-               break;
-
-       /* query or set current channel's PCM data format */
-       case SNDCTL_DSP_SETFMT:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_SETFMT, val==%d\n", val);
-               if (val != AFMT_QUERY) {
-                       rc = 0;
-
-                       if (rd)
-                               rc = via_chan_set_fmt (card, &card->ch_in, val);
-
-                       if (rc >= 0 && wr)
-                               rc = via_chan_set_fmt (card, &card->ch_out, val);
-
-                       if (rc < 0)
-                               break;
-
-                       val = rc;
-               } else {
-                       if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) ||
-                           (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_16BIT)))
-                               val = AFMT_S16_LE;
-                       else
-                               val = AFMT_U8;
-               }
-               DPRINTK ("SETFMT EXIT, returning %d\n", val);
-                rc = put_user (val, ip);
-               break;
-
-       /* query or set number of channels (1=mono, 2=stereo, 4/6 for multichannel) */
-        case SNDCTL_DSP_CHANNELS:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_CHANNELS, val==%d\n", val);
-               if (val != 0) {
-                       rc = 0;
-
-                       if (rd)
-                               rc = via_chan_set_stereo (card, &card->ch_in, val);
-
-                       if (rc >= 0 && wr)
-                               rc = via_chan_set_stereo (card, &card->ch_out, val);
-
-                       if (rc < 0)
-                               break;
-
-                       val = rc;
-               } else {
-                       if (rd)
-                               val = card->ch_in.channels;
-                       else
-                               val = card->ch_out.channels;
-               }
-               DPRINTK ("CHANNELS EXIT, returning %d\n", val);
-                rc = put_user (val, ip);
-               break;
-
-       /* enable (val is not zero) or disable (val == 0) stereo */
-        case SNDCTL_DSP_STEREO:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_STEREO, val==%d\n", val);
-               rc = 0;
-
-               if (rd)
-                       rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1);
-               if (rc >= 0 && wr)
-                       rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1);
-
-               if (rc < 0)
-                       break;
-
-               val = rc - 1;
-
-               DPRINTK ("STEREO EXIT, returning %d\n", val);
-               rc = put_user(val, ip);
-               break;
-
-       /* query or set sampling rate */
-        case SNDCTL_DSP_SPEED:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_SPEED, val==%d\n", val);
-               if (val < 0) {
-                       rc = -EINVAL;
-                       break;
-               }
-               if (val > 0) {
-                       rc = 0;
-
-                       if (rd)
-                               rc = via_chan_set_speed (card, &card->ch_in, val);
-                       if (rc >= 0 && wr)
-                               rc = via_chan_set_speed (card, &card->ch_out, val);
-
-                       if (rc < 0)
-                               break;
-
-                       val = rc;
-               } else {
-                       if (rd)
-                               val = card->ch_in.rate;
-                       else if (wr)
-                               val = card->ch_out.rate;
-                       else
-                               val = 0;
-               }
-               DPRINTK ("SPEED EXIT, returning %d\n", val);
-                rc = put_user (val, ip);
-               break;
-
-       /* wait until all buffers have been played, and then stop device */
-       case SNDCTL_DSP_SYNC:
-               DPRINTK ("DSP_SYNC\n");
-               rc = 0;
-               if (wr) {
-                       DPRINTK ("SYNC EXIT (after calling via_dsp_drain_playback)\n");
-                       rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
-               }
-               break;
-
-       /* stop recording/playback immediately */
-        case SNDCTL_DSP_RESET:
-               DPRINTK ("DSP_RESET\n");
-               if (rd) {
-                       via_chan_clear (card, &card->ch_in);
-                       card->ch_in.frag_number = 0;
-                       card->ch_in.frag_size = 0;
-                       atomic_set(&card->ch_in.n_frags, 0);
-               }
-
-               if (wr) {
-                       via_chan_clear (card, &card->ch_out);
-                       card->ch_out.frag_number = 0;
-                       card->ch_out.frag_size = 0;
-                       atomic_set(&card->ch_out.n_frags, 0);
-               }
-
-               rc = 0;
-               break;
-
-       case SNDCTL_DSP_NONBLOCK:
-               file->f_flags |= O_NONBLOCK;
-               rc = 0;
-               break;
-
-       /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
-       case SNDCTL_DSP_GETCAPS:
-               DPRINTK ("DSP_GETCAPS\n");
-               rc = put_user(VIA_DSP_CAP, ip);
-               break;
-
-       /* obtain buffer fragment size */
-       case SNDCTL_DSP_GETBLKSIZE:
-               DPRINTK ("DSP_GETBLKSIZE\n");
-
-               if (rd) {
-                       via_chan_set_buffering(card, &card->ch_in, -1);
-                       rc = put_user(card->ch_in.frag_size, ip);
-               } else if (wr) {
-                       via_chan_set_buffering(card, &card->ch_out, -1);
-                       rc = put_user(card->ch_out.frag_size, ip);
-               }
-               break;
-
-       /* obtain information about input buffering */
-       case SNDCTL_DSP_GETISPACE:
-               DPRINTK ("DSP_GETISPACE\n");
-               if (rd)
-                       rc = via_dsp_ioctl_space (card, &card->ch_in, p);
-               break;
-
-       /* obtain information about output buffering */
-       case SNDCTL_DSP_GETOSPACE:
-               DPRINTK ("DSP_GETOSPACE\n");
-               if (wr)
-                       rc = via_dsp_ioctl_space (card, &card->ch_out, p);
-               break;
-
-       /* obtain information about input hardware pointer */
-       case SNDCTL_DSP_GETIPTR:
-               DPRINTK ("DSP_GETIPTR\n");
-               if (rd)
-                       rc = via_dsp_ioctl_ptr (card, &card->ch_in, p);
-               break;
-
-       /* obtain information about output hardware pointer */
-       case SNDCTL_DSP_GETOPTR:
-               DPRINTK ("DSP_GETOPTR\n");
-               if (wr)
-                       rc = via_dsp_ioctl_ptr (card, &card->ch_out, p);
-               break;
-
-       /* return number of bytes remaining to be played by DMA engine */
-       case SNDCTL_DSP_GETODELAY:
-               {
-               DPRINTK ("DSP_GETODELAY\n");
-
-               chan = &card->ch_out;
-
-               if (!wr)
-                       break;
-
-               if (chan->is_active) {
-
-                       val = chan->frag_number - atomic_read (&chan->n_frags);
-
-                       assert(val >= 0);
-                               
-                       if (val > 0) {
-                               val *= chan->frag_size;
-                               val -= chan->frag_size - via_sg_offset(chan);
-                       }
-                       val += chan->slop_len % chan->frag_size;
-               } else
-                       val = 0;
-
-               assert (val <= (chan->frag_size * chan->frag_number));
-
-               DPRINTK ("GETODELAY EXIT, val = %d bytes\n", val);
-                rc = put_user (val, ip);
-               break;
-               }
-
-       /* handle the quick-start of a channel,
-        * or the notification that a quick-start will
-        * occur in the future
-        */
-       case SNDCTL_DSP_SETTRIGGER:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n",
-                       rd, wr, card->ch_in.is_active, card->ch_out.is_active,
-                       card->ch_in.is_enabled, card->ch_out.is_enabled);
-
-               rc = 0;
-
-               if (rd)
-                       rc = via_dsp_ioctl_trigger (&card->ch_in, val);
-
-               if (!rc && wr)
-                       rc = via_dsp_ioctl_trigger (&card->ch_out, val);
-
-               break;
-
-       case SNDCTL_DSP_GETTRIGGER:
-               val = 0;
-               if ((file->f_mode & FMODE_READ) && card->ch_in.is_enabled)
-                       val |= PCM_ENABLE_INPUT;
-               if ((file->f_mode & FMODE_WRITE) && card->ch_out.is_enabled)
-                       val |= PCM_ENABLE_OUTPUT;
-               rc = put_user(val, ip);
-               break;
-
-       /* Enable full duplex.  Since we do this as soon as we are opened
-        * with O_RDWR, this is mainly a no-op that always returns success.
-        */
-       case SNDCTL_DSP_SETDUPLEX:
-               DPRINTK ("DSP_SETDUPLEX\n");
-               if (!rd || !wr)
-                       break;
-               rc = 0;
-               break;
-
-       /* set fragment size.  implemented as a successful no-op for now */
-       case SNDCTL_DSP_SETFRAGMENT:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_SETFRAGMENT, val==%d\n", val);
-
-               if (rd)
-                       rc = via_chan_set_buffering(card, &card->ch_in, val);
-
-               if (wr)
-                       rc = via_chan_set_buffering(card, &card->ch_out, val);
-
-               DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n",
-                        val & 0xFFFF,
-                        val & 0xFFFF,
-                        (val >> 16) & 0xFFFF,
-                        (val >> 16) & 0xFFFF);
-
-               rc = 0;
-               break;
-
-       /* inform device of an upcoming pause in input (or output). */
-       case SNDCTL_DSP_POST:
-               DPRINTK ("DSP_POST\n");
-               if (wr) {
-                       if (card->ch_out.slop_len > 0)
-                               via_chan_flush_frag (&card->ch_out);
-                       via_chan_maybe_start (&card->ch_out);
-               }
-
-               rc = 0;
-               break;
-
-       /* not implemented */
-       default:
-               DPRINTK ("unhandled ioctl, cmd==%u, arg==%p\n",
-                        cmd, p);
-               break;
-       }
-
-       mutex_unlock(&card->syscall_mutex);
-       DPRINTK ("EXIT, returning %d\n", rc);
-       return rc;
-}
-
-
-static int via_dsp_open (struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct via_info *card;
-       struct pci_dev *pdev = NULL;
-       struct via_channel *chan;
-       struct pci_driver *drvr;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-
-       DPRINTK ("ENTER, minor=%d, file->f_mode=0x%x\n", minor, file->f_mode);
-
-       if (!(file->f_mode & (FMODE_READ | FMODE_WRITE))) {
-               DPRINTK ("EXIT, returning -EINVAL\n");
-               return -EINVAL;
-       }
-
-       card = NULL;
-       while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
-               drvr = pci_dev_driver (pdev);
-               if (drvr == &via_driver) {
-                       assert (pci_get_drvdata (pdev) != NULL);
-
-                       card = pci_get_drvdata (pdev);
-                       DPRINTK ("dev_dsp = %d, minor = %d, assn = %d\n",
-                                card->dev_dsp, minor,
-                                (card->dev_dsp ^ minor) & ~0xf);
-
-                       if (((card->dev_dsp ^ minor) & ~0xf) == 0)
-                               goto match;
-               }
-       }
-
-       DPRINTK ("no matching %s found\n", card ? "minor" : "driver");
-       return -ENODEV;
-
-match:
-       pci_dev_put(pdev);
-       if (nonblock) {
-               if (!mutex_trylock(&card->open_mutex)) {
-                       DPRINTK ("EXIT, returning -EAGAIN\n");
-                       return -EAGAIN;
-               }
-       } else {
-               if (mutex_lock_interruptible(&card->open_mutex)) {
-                       DPRINTK ("EXIT, returning -ERESTARTSYS\n");
-                       return -ERESTARTSYS;
-               }
-       }
-
-       file->private_data = card;
-       DPRINTK ("file->f_mode == 0x%x\n", file->f_mode);
-
-       /* handle input from analog source */
-       if (file->f_mode & FMODE_READ) {
-               chan = &card->ch_in;
-
-               via_chan_init (card, chan);
-
-               /* why is this forced to 16-bit stereo in all drivers? */
-               chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
-               chan->channels = 2;
-
-               // TO DO - use FIFO: via_capture_fifo(card, 1);
-               via_chan_pcm_fmt (chan, 0);
-               via_set_rate (card->ac97, chan, 44100);
-       }
-
-       /* handle output to analog source */
-       if (file->f_mode & FMODE_WRITE) {
-               chan = &card->ch_out;
-
-               via_chan_init (card, chan);
-
-               if (file->f_mode & FMODE_READ) {
-                       /* if in duplex mode make the recording and playback channels
-                          have the same settings */
-                       chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
-                       chan->channels = 2;
-                       via_chan_pcm_fmt (chan, 0);
-                        via_set_rate (card->ac97, chan, 44100);
-               } else {
-                        if ((minor & 0xf) == SND_DEV_DSP16) {
-                               chan->pcm_fmt = VIA_PCM_FMT_16BIT;
-                               via_chan_pcm_fmt (chan, 0);
-                               via_set_rate (card->ac97, chan, 44100);
-                       } else {
-                               via_chan_pcm_fmt (chan, 1);
-                               via_set_rate (card->ac97, chan, 8000);
-                       }
-               }
-       }
-
-       DPRINTK ("EXIT, returning 0\n");
-       return nonseekable_open(inode, file);
-}
-
-
-static int via_dsp_release(struct inode *inode, struct file *file)
-{
-       struct via_info *card;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int rc;
-
-       DPRINTK ("ENTER\n");
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) {
-               DPRINTK ("EXIT (syscall_down error), rc=%d\n", rc);
-               return rc;
-       }
-
-       if (file->f_mode & FMODE_WRITE) {
-               rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
-               if (rc && rc != -ERESTARTSYS)   /* Nobody needs to know about ^C */
-                       printk (KERN_DEBUG "via_audio: ignoring drain playback error %d\n", rc);
-
-               via_chan_free (card, &card->ch_out);
-               via_chan_buffer_free(card, &card->ch_out);
-       }
-
-       if (file->f_mode & FMODE_READ) {
-               via_chan_free (card, &card->ch_in);
-               via_chan_buffer_free (card, &card->ch_in);
-       }
-
-       mutex_unlock(&card->syscall_mutex);
-       mutex_unlock(&card->open_mutex);
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-/****************************************************************
- *
- * Chip setup and kernel registration
- *
- *
- */
-
-static int __devinit via_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
-{
-#ifdef CONFIG_MIDI_VIA82CXXX
-       u8 r42;
-#endif
-       int rc;
-       struct via_info *card;
-       static int printed_version;
-
-       DPRINTK ("ENTER\n");
-
-       if (printed_version++ == 0)
-               printk (KERN_INFO "Via 686a/8233/8235 audio driver " VIA_VERSION "\n");
-
-       rc = pci_enable_device (pdev);
-       if (rc)
-               goto err_out;
-
-       rc = pci_request_regions (pdev, "via82cxxx_audio");
-       if (rc)
-               goto err_out_disable;
-
-       rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-       if (rc)
-               goto err_out_res;
-       rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
-       if (rc)
-               goto err_out_res;
-
-       card = kmalloc (sizeof (*card), GFP_KERNEL);
-       if (!card) {
-               printk (KERN_ERR PFX "out of memory, aborting\n");
-               rc = -ENOMEM;
-               goto err_out_res;
-       }
-
-       pci_set_drvdata (pdev, card);
-
-       memset (card, 0, sizeof (*card));
-       card->pdev = pdev;
-       card->baseaddr = pci_resource_start (pdev, 0);
-       card->card_num = via_num_cards++;
-       spin_lock_init (&card->lock);
-       spin_lock_init (&card->ac97_lock);
-       mutex_init(&card->syscall_mutex);
-       mutex_init(&card->open_mutex);
-
-       /* we must init these now, in case the intr handler needs them */
-       via_chan_init_defaults (card, &card->ch_out);
-       via_chan_init_defaults (card, &card->ch_in);
-       via_chan_init_defaults (card, &card->ch_fm);
-
-       /* if BAR 2 is present, chip is Rev H or later,
-        * which means it has a few extra features */
-       if (pci_resource_start (pdev, 2) > 0)
-               card->rev_h = 1;
-               
-       /* Overkill for now, but more flexible done right */
-       
-       card->intmask = id->driver_data;
-       card->legacy = !card->intmask;
-       card->sixchannel = id->driver_data;
-       
-       if(card->sixchannel)
-               printk(KERN_INFO PFX "Six channel audio available\n");
-       if (pdev->irq < 1) {
-               printk (KERN_ERR PFX "invalid PCI IRQ %d, aborting\n", pdev->irq);
-               rc = -ENODEV;
-               goto err_out_kfree;
-       }
-
-       if (!(pci_resource_flags (pdev, 0) & IORESOURCE_IO)) {
-               printk (KERN_ERR PFX "unable to locate I/O resources, aborting\n");
-               rc = -ENODEV;
-               goto err_out_kfree;
-       }
-
-       pci_set_master(pdev);
-       
-       /*
-        * init AC97 mixer and codec
-        */
-       rc = via_ac97_init (card);
-       if (rc) {
-               printk (KERN_ERR PFX "AC97 init failed, aborting\n");
-               goto err_out_kfree;
-       }
-
-       /*
-        * init DSP device
-        */
-       rc = via_dsp_init (card);
-       if (rc) {
-               printk (KERN_ERR PFX "DSP device init failed, aborting\n");
-               goto err_out_have_mixer;
-       }
-
-       /*
-        * init and turn on interrupts, as the last thing we do
-        */
-       rc = via_interrupt_init (card);
-       if (rc) {
-               printk (KERN_ERR PFX "interrupt init failed, aborting\n");
-               goto err_out_have_dsp;
-       }
-
-       printk (KERN_INFO PFX "board #%d at 0x%04lX, IRQ %d\n",
-               card->card_num + 1, card->baseaddr, pdev->irq);
-
-#ifdef CONFIG_MIDI_VIA82CXXX
-       /* Disable by default */
-       card->midi_info.io_base = 0;
-
-       if(card->legacy)
-       {
-               pci_read_config_byte (pdev, 0x42, &r42);
-               /* Disable MIDI interrupt */
-               pci_write_config_byte (pdev, 0x42, r42 | VIA_CR42_MIDI_IRQMASK);
-               if (r42 & VIA_CR42_MIDI_ENABLE)
-               {
-                       if (r42 & VIA_CR42_MIDI_PNP) /* Address selected by iobase 2 - not tested */
-                               card->midi_info.io_base = pci_resource_start (pdev, 2);
-                       else /* Address selected by byte 0x43 */
-                       {
-                               u8 r43;
-                               pci_read_config_byte (pdev, 0x43, &r43);
-                               card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2);
-                       }
-
-                       card->midi_info.irq = -pdev->irq;
-                       if (probe_uart401(& card->midi_info, THIS_MODULE))
-                       {
-                               card->midi_devc=midi_devs[card->midi_info.slots[4]]->devc;
-                               pci_write_config_byte(pdev, 0x42, r42 & ~VIA_CR42_MIDI_IRQMASK);
-                               printk("Enabled Via MIDI\n");
-                       }
-               }
-       }
-#endif
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-
-err_out_have_dsp:
-       via_dsp_cleanup (card);
-
-err_out_have_mixer:
-       via_ac97_cleanup (card);
-
-err_out_kfree:
-#ifndef VIA_NDEBUG
-       memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
-#endif
-       kfree (card);
-
-err_out_res:
-       pci_release_regions (pdev);
-
-err_out_disable:
-       pci_disable_device (pdev);
-
-err_out:
-       pci_set_drvdata (pdev, NULL);
-       DPRINTK ("EXIT - returning %d\n", rc);
-       return rc;
-}
-
-
-static void __devexit via_remove_one (struct pci_dev *pdev)
-{
-       struct via_info *card;
-
-       DPRINTK ("ENTER\n");
-
-       assert (pdev != NULL);
-       card = pci_get_drvdata (pdev);
-       assert (card != NULL);
-
-#ifdef CONFIG_MIDI_VIA82CXXX
-       if (card->midi_info.io_base)
-               unload_uart401(&card->midi_info);
-#endif
-
-       free_irq (card->pdev->irq, card);
-       via_dsp_cleanup (card);
-       via_ac97_cleanup (card);
-
-#ifndef VIA_NDEBUG
-       memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
-#endif
-       kfree (card);
-
-       pci_set_drvdata (pdev, NULL);
-
-       pci_release_regions (pdev);
-       pci_disable_device (pdev);
-       pci_set_power_state (pdev, 3); /* ...zzzzzz */
-
-       DPRINTK ("EXIT\n");
-       return;
-}
-
-
-/****************************************************************
- *
- * Driver initialization and cleanup
- *
- *
- */
-
-static int __init init_via82cxxx_audio(void)
-{
-       int rc;
-
-       DPRINTK ("ENTER\n");
-
-       rc = pci_register_driver (&via_driver);
-       if (rc) {
-               DPRINTK ("EXIT, returning %d\n", rc);
-               return rc;
-       }
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-static void __exit cleanup_via82cxxx_audio(void)
-{
-       DPRINTK ("ENTER\n");
-
-       pci_unregister_driver (&via_driver);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-module_init(init_via82cxxx_audio);
-module_exit(cleanup_via82cxxx_audio);
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("DSP audio and mixer driver for Via 82Cxxx audio devices");
-MODULE_LICENSE("GPL");
-