Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 7 Feb 2008 18:21:26 +0000 (10:21 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 7 Feb 2008 18:21:26 +0000 (10:21 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC32]: Use regsets in arch_ptrace().
  [SPARC64]: Use regsets in arch_ptrace().
  [SPARC32]: Use regsets for ELF core dumping.
  [SPARC64]: Use regsets for ELF core dumping.
  [SPARC64]: Remove unintentional ptrace debugging messages.
  [SPARC]: Move over to arch_ptrace().
  [SPARC]: Remove PTRACE_SUN* handling.
  [SPARC]: Kill DEBUG_PTRACE code.
  [SPARC32]: Add user regset support.
  [SPARC64]: Add user regsets.
  [SPARC64]: Fix booting on non-zero cpu.

722 files changed:
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-firmware-acpi [new file with mode: 0644]
Documentation/ABI/testing/sysfs-kernel-uids
Documentation/DocBook/genericirq.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/acpi/dsdt-override.txt [new file with mode: 0644]
Documentation/acpi/initramfs-add-dsdt.sh [new file with mode: 0755]
Documentation/acpi/method-tracing.txt [new file with mode: 0644]
Documentation/cgroups.txt
Documentation/controllers/memory.txt [new file with mode: 0644]
Documentation/cpusets.txt
Documentation/edac.txt [moved from Documentation/drivers/edac/edac.txt with 100% similarity]
Documentation/email-clients.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/00-INDEX
Documentation/filesystems/Locking
Documentation/filesystems/dnotify.txt [moved from Documentation/dnotify.txt with 99% similarity]
Documentation/filesystems/porting
Documentation/filesystems/sharedsubtree.txt [moved from Documentation/sharedsubtree.txt with 100% similarity]
Documentation/filesystems/vfs.txt
Documentation/kernel-parameters.txt
Documentation/leds-class.txt
Documentation/power/swsusp.txt
Documentation/powerpc/booting-without-of.txt
Documentation/scheduler/00-INDEX [new file with mode: 0644]
Documentation/scheduler/sched-arch.txt [moved from Documentation/sched-arch.txt with 100% similarity]
Documentation/scheduler/sched-coding.txt [moved from Documentation/sched-coding.txt with 100% similarity]
Documentation/scheduler/sched-design-CFS.txt [moved from Documentation/sched-design-CFS.txt with 100% similarity]
Documentation/scheduler/sched-design.txt [moved from Documentation/sched-design.txt with 100% similarity]
Documentation/scheduler/sched-domains.txt [moved from Documentation/sched-domains.txt with 100% similarity]
Documentation/scheduler/sched-nice-design.txt [moved from Documentation/sched-nice-design.txt with 100% similarity]
Documentation/scheduler/sched-stats.txt [moved from Documentation/sched-stats.txt with 100% similarity]
Documentation/sysctl/vm.txt
Documentation/thermal/sysfs-api.txt [new file with mode: 0644]
Documentation/thinkpad-acpi.txt
MAINTAINERS
REPORTING-BUGS
arch/alpha/kernel/core_irongate.c
arch/alpha/kernel/setup.c
arch/alpha/mm/numa.c
arch/arm/mach-ixp4xx/dsmg600-setup.c
arch/arm/mach-ixp4xx/nas100d-setup.c
arch/arm/mach-ixp4xx/nslu2-setup.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/blackfin/kernel/setup.c
arch/cris/kernel/setup.c
arch/frv/kernel/setup.c
arch/h8300/kernel/setup.c
arch/ia64/kernel/acpi-processor.c
arch/ia64/kernel/acpi.c
arch/ia64/kernel/machine_kexec.c
arch/ia64/mm/contig.c
arch/ia64/mm/discontig.c
arch/m32r/kernel/setup.c
arch/m32r/kernel/smpboot.c
arch/m32r/mm/discontig.c
arch/m68k/atari/stram.c
arch/m68k/kernel/setup.c
arch/m68knommu/kernel/setup.c
arch/mips/kernel/setup.c
arch/mips/sgi-ip27/ip27-memory.c
arch/parisc/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/boot/Makefile
arch/powerpc/boot/cuboot-mpc7448hpc2.c [moved from arch/powerpc/boot/cuboot-hpc2.c with 100% similarity]
arch/powerpc/boot/dts/adder875-redboot.dts
arch/powerpc/boot/dts/adder875-uboot.dts
arch/powerpc/boot/dts/mpc5121ads.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8313erdb.dts
arch/powerpc/boot/dts/mpc8315erdb.dts
arch/powerpc/boot/dts/mpc834x_mds.dts
arch/powerpc/boot/dts/mpc8572ds.dts
arch/powerpc/boot/dts/mpc885ads.dts
arch/powerpc/boot/dts/sequoia.dts
arch/powerpc/boot/dts/storcenter.dts
arch/powerpc/boot/wrapper
arch/powerpc/configs/mpc83xx_defconfig
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/binfmt_elf32.c [deleted file]
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/legacy_serial.c
arch/powerpc/kernel/pmc.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/ptrace32.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vio.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/numa.c
arch/powerpc/oprofile/Makefile
arch/powerpc/oprofile/common.c
arch/powerpc/oprofile/op_model_fsl_emb.c [moved from arch/powerpc/oprofile/op_model_fsl_booke.c with 90% similarity]
arch/powerpc/platforms/40x/Kconfig
arch/powerpc/platforms/40x/virtex.c
arch/powerpc/platforms/40x/walnut.c
arch/powerpc/platforms/44x/warp.c
arch/powerpc/platforms/512x/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/512x/Makefile [new file with mode: 0644]
arch/powerpc/platforms/512x/mpc5121_ads.c [new file with mode: 0644]
arch/powerpc/platforms/82xx/mpc8272_ads.c
arch/powerpc/platforms/82xx/pq2fads.c
arch/powerpc/platforms/83xx/mpc832x_rdb.c
arch/powerpc/platforms/83xx/mpc83xx.h
arch/powerpc/platforms/83xx/usb.c
arch/powerpc/platforms/8xx/adder875.c
arch/powerpc/platforms/8xx/ep88xc.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/Makefile
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/cell/setup.c
arch/powerpc/platforms/cell/spufs/Makefile
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/run.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/spufs.h
arch/powerpc/platforms/cell/spufs/sputrace.c [new file with mode: 0644]
arch/powerpc/platforms/embedded6xx/storcenter.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/kexec.c
arch/powerpc/platforms/pseries/reconfig.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/platforms/pseries/xics.h
arch/powerpc/sysdev/dcr.c
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/mpc8xx_pic.c
arch/powerpc/sysdev/qe_lib/qe.c
arch/s390/kernel/setup.c
arch/sh/kernel/setup.c
arch/sh/mm/numa.c
arch/sparc/mm/init.c
arch/sparc64/mm/init.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/ia32/ia32_aout.c
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/processor.c
arch/x86/kernel/cpu/cpufreq/Kconfig
arch/x86/kernel/cpu/cpufreq/e_powersaver.c
arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
arch/x86/kernel/cpu/cpufreq/powernow-k7.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.h
arch/x86/kernel/cpu/cpufreq/speedstep-lib.c
arch/x86/kernel/machine_kexec_32.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/mpparse_32.c
arch/x86/kernel/setup_32.c
arch/x86/kernel/setup_64.c
arch/x86/kernel/srat_32.c
arch/x86/mm/discontig_32.c
arch/x86/mm/init_64.c
arch/x86/mm/numa_64.c
arch/x86/mm/srat_64.c
crypto/cbc.c
crypto/cryptd.c
crypto/ecb.c
crypto/hmac.c
crypto/lrw.c
crypto/pcbc.c
crypto/xcbc.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/asus_acpi.c
drivers/acpi/battery.c
drivers/acpi/bay.c
drivers/acpi/blacklist.c
drivers/acpi/bus.c
drivers/acpi/debug.c
drivers/acpi/dispatcher/dsopcode.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/event.c
drivers/acpi/events/evevent.c
drivers/acpi/events/evgpe.c
drivers/acpi/fan.c
drivers/acpi/glue.c
drivers/acpi/hardware/hwsleep.c
drivers/acpi/namespace/nsxfeval.c
drivers/acpi/numa.c
drivers/acpi/osl.c
drivers/acpi/pci_bind.c
drivers/acpi/pci_irq.c
drivers/acpi/pci_link.c
drivers/acpi/power.c
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_perflib.c
drivers/acpi/processor_thermal.c
drivers/acpi/processor_throttling.c
drivers/acpi/sbs.c
drivers/acpi/sbshc.c
drivers/acpi/scan.c
drivers/acpi/sleep/main.c
drivers/acpi/sleep/proc.c
drivers/acpi/system.c
drivers/acpi/tables/Makefile
drivers/acpi/tables/tbxfroot.c
drivers/acpi/thermal.c
drivers/acpi/utilities/utglobal.c
drivers/acpi/video.c
drivers/acpi/wmi.c [new file with mode: 0644]
drivers/block/xsysace.c
drivers/cdrom/viocd.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/drm/Kconfig
drivers/char/drm/Makefile
drivers/char/drm/README.drm
drivers/char/drm/ati_pcigart.c
drivers/char/drm/drm.h
drivers/char/drm/drmP.h
drivers/char/drm/drm_agpsupport.c
drivers/char/drm/drm_bufs.c
drivers/char/drm/drm_context.c
drivers/char/drm/drm_drv.c
drivers/char/drm/drm_hashtab.c
drivers/char/drm/drm_hashtab.h
drivers/char/drm/drm_ioc32.c
drivers/char/drm/drm_ioctl.c
drivers/char/drm/drm_irq.c
drivers/char/drm/drm_memory.c
drivers/char/drm/drm_mm.c
drivers/char/drm/drm_os_linux.h
drivers/char/drm/drm_pciids.h
drivers/char/drm/drm_proc.c
drivers/char/drm/drm_sarea.h
drivers/char/drm/drm_scatter.c
drivers/char/drm/drm_stub.c
drivers/char/drm/drm_sysfs.c
drivers/char/drm/drm_vm.c
drivers/char/drm/i810_dma.c
drivers/char/drm/i810_drv.h
drivers/char/drm/i830_dma.c
drivers/char/drm/i830_drm.h
drivers/char/drm/i830_drv.h
drivers/char/drm/i830_irq.c
drivers/char/drm/i915_dma.c
drivers/char/drm/i915_drv.c
drivers/char/drm/i915_drv.h
drivers/char/drm/i915_irq.c
drivers/char/drm/i915_mem.c
drivers/char/drm/mga_dma.c
drivers/char/drm/mga_drv.h
drivers/char/drm/mga_state.c
drivers/char/drm/r128_cce.c
drivers/char/drm/r128_drv.h
drivers/char/drm/r128_state.c
drivers/char/drm/r300_cmdbuf.c
drivers/char/drm/r300_reg.h
drivers/char/drm/radeon_cp.c
drivers/char/drm/radeon_drm.h
drivers/char/drm/radeon_drv.h
drivers/char/drm/radeon_irq.c
drivers/char/drm/radeon_mem.c
drivers/char/drm/radeon_state.c
drivers/char/drm/savage_state.c
drivers/char/drm/sis_mm.c
drivers/char/drm/via_dma.c
drivers/char/drm/via_dmablit.c
drivers/char/drm/via_dmablit.h
drivers/char/drm/via_drm.h
drivers/char/drm/via_drv.c
drivers/char/drm/via_irq.c
drivers/char/drm/via_map.c
drivers/char/drm/via_mm.c
drivers/char/drm/via_video.c
drivers/char/epca.h
drivers/char/esp.c
drivers/char/i8k.c
drivers/char/ip2/ip2main.c
drivers/char/istallion.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/riscom8.c
drivers/char/riscom8.h
drivers/char/rocket.c
drivers/char/rocket_int.h
drivers/char/serial167.c
drivers/char/specialix.c
drivers/char/specialix_io8.h
drivers/char/stallion.c
drivers/char/sx.h
drivers/char/xilinx_hwicap/Makefile [new file with mode: 0644]
drivers/char/xilinx_hwicap/buffer_icap.c [new file with mode: 0644]
drivers/char/xilinx_hwicap/buffer_icap.h [new file with mode: 0644]
drivers/char/xilinx_hwicap/fifo_icap.c [new file with mode: 0644]
drivers/char/xilinx_hwicap/fifo_icap.h [new file with mode: 0644]
drivers/char/xilinx_hwicap/xilinx_hwicap.c [new file with mode: 0644]
drivers/char/xilinx_hwicap/xilinx_hwicap.h [new file with mode: 0644]
drivers/cpufreq/Kconfig
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_userspace.c
drivers/cpufreq/freq_table.c
drivers/cpuidle/Kconfig
drivers/cpuidle/cpuidle.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/dmi_scan.c
drivers/hwmon/applesmc.c
drivers/input/misc/wistron_btns.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-ams-delta.c
drivers/leds/leds-clevo-mail.c [new file with mode: 0644]
drivers/leds/leds-corgi.c
drivers/leds/leds-gpio.c
drivers/leds/leds-hp6xx.c [new file with mode: 0644]
drivers/leds/leds-ixp4xx-gpio.c [deleted file]
drivers/leds/leds-locomo.c
drivers/leds/leds-net48xx.c
drivers/leds/leds-spitz.c
drivers/leds/leds-tosa.c
drivers/leds/leds-wrap.c
drivers/leds/ledtrig-timer.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/asic3.c [new file with mode: 0644]
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/acer-wmi.c [new file with mode: 0644]
drivers/misc/asus-laptop.c
drivers/misc/intel_menlow.c [new file with mode: 0644]
drivers/misc/sony-laptop.c
drivers/misc/tc1100-wmi.c [new file with mode: 0644]
drivers/misc/thinkpad_acpi.c
drivers/misc/thinkpad_acpi.h [deleted file]
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/cfi_probe.c
drivers/mtd/chips/gen_probe.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/doc2000.c
drivers/mtd/devices/doc2001plus.c
drivers/mtd/devices/lart.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/physmap.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/pnc2000.c [deleted file]
drivers/mtd/maps/scb2_flash.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdoops.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/at91_nand.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/fsl_elbc_nand.c [new file with mode: 0644]
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/orion_nand.c [new file with mode: 0644]
drivers/mtd/nand/pasemi_nand.c [new file with mode: 0644]
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/ofpart.c [new file with mode: 0644]
drivers/mtd/onenand/onenand_base.c
drivers/mtd/redboot.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/gluebi.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/kapi.c
drivers/mtd/ubi/misc.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/upd.c
drivers/mtd/ubi/vmt.c
drivers/mtd/ubi/vtbl.c
drivers/mtd/ubi/wl.c
drivers/net/Kconfig
drivers/net/cpmac.c
drivers/net/wireless/b43/leds.c
drivers/of/base.c
drivers/of/platform.c
drivers/pnp/pnpacpi/core.c
drivers/power/power_supply_sysfs.c
drivers/serial/68328serial.c
drivers/serial/Kconfig
drivers/serial/crisv10.c
drivers/serial/dz.c
drivers/serial/dz.h
drivers/serial/mpc52xx_uart.c
drivers/serial/uartlite.c
drivers/thermal/Kconfig [new file with mode: 0644]
drivers/thermal/Makefile [new file with mode: 0644]
drivers/thermal/thermal.c [new file with mode: 0644]
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/backlight.c
drivers/video/backlight/omap1_bl.c [new file with mode: 0644]
drivers/video/xilinxfb.c
drivers/w1/masters/ds1wm.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/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/inode.c
fs/compat_ioctl.c
fs/efs/inode.c
fs/efs/namei.c
fs/efs/super.c
fs/ext2/ext2.h
fs/ext2/inode.c
fs/ext2/namei.c
fs/ext2/super.c
fs/ext3/ialloc.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext3/resize.c
fs/ext3/super.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/resize.c
fs/ext4/super.c
fs/fat/inode.c
fs/freevxfs/vxfs_extern.h
fs/freevxfs/vxfs_inode.c
fs/freevxfs/vxfs_lookup.c
fs/freevxfs/vxfs_super.c
fs/fuse/dir.c
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/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/ioctl.c
fs/isofs/export.c
fs/isofs/inode.c
fs/isofs/namei.c
fs/isofs/rock.c
fs/jffs2/acl.c
fs/jffs2/acl.h
fs/jffs2/dir.c
fs/jffs2/fs.c
fs/jffs2/nodelist.c
fs/jffs2/os-linux.h
fs/jffs2/readinode.c
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/nfs/getroot.c
fs/nfsd/export.c
fs/openpromfs/inode.c
fs/proc/inode.c
fs/qnx4/inode.c
fs/qnx4/namei.c
fs/quota.c
fs/reiserfs/inode.c
fs/reiserfs/xattr.c
fs/romfs/inode.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/vfat/namei.c
include/acpi/acglobal.h
include/acpi/acmacros.h
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/acpi/acpi_numa.h
include/acpi/acpiosxf.h
include/acpi/processor.h
include/asm-alpha/elf.h
include/asm-alpha/page.h
include/asm-alpha/system.h
include/asm-alpha/user.h
include/asm-arm/elf.h
include/asm-arm/page.h
include/asm-arm/system.h
include/asm-arm/user.h
include/asm-avr32/elf.h
include/asm-avr32/page.h
include/asm-avr32/system.h
include/asm-avr32/user.h
include/asm-blackfin/elf.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-h8300/elf.h
include/asm-h8300/page.h
include/asm-h8300/system.h
include/asm-h8300/user.h
include/asm-ia64/elf.h
include/asm-ia64/intrinsics.h
include/asm-ia64/page.h
include/asm-ia64/user.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/motorola_pgtable.h
include/asm-m68k/page.h
include/asm-m68k/system.h
include/asm-m68k/user.h
include/asm-m68knommu/elf.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/cputable.h
include/asm-powerpc/dcr-native.h
include/asm-powerpc/elf.h
include/asm-powerpc/mpc512x.h [new file with mode: 0644]
include/asm-powerpc/mpc52xx_psc.h
include/asm-powerpc/oprofile_impl.h
include/asm-powerpc/page.h
include/asm-powerpc/page_32.h
include/asm-powerpc/page_64.h
include/asm-powerpc/ptrace.h
include/asm-powerpc/reg.h
include/asm-powerpc/reg_booke.h
include/asm-powerpc/reg_fsl_emb.h [new file with mode: 0644]
include/asm-powerpc/system.h
include/asm-powerpc/user.h
include/asm-powerpc/vio.h
include/asm-ppc/system.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/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-sparc64/elf.h
include/asm-sparc64/page.h
include/asm-sparc64/system.h
include/asm-v850/elf.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/elf.h
include/asm-x86/mmzone_32.h
include/asm-x86/termios.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/acpi.h
include/linux/bootmem.h
include/linux/cgroup.h
include/linux/cgroup_subsys.h
include/linux/cpufreq.h
include/linux/cpuidle.h
include/linux/dmi.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/hayesesp.h
include/linux/isicom.h
include/linux/istallion.h
include/linux/kernel.h
include/linux/kexec.h
include/linux/leds.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/mtd/cfi.h
include/linux/mtd/mtd.h
include/linux/mtd/mtdram.h [new file with mode: 0644]
include/linux/mtd/onenand_regs.h
include/linux/mtd/partitions.h
include/linux/mtd/ubi.h
include/linux/of.h
include/linux/power_supply.h
include/linux/qnx4_fs.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/sonypi.h
include/linux/stallion.h
include/linux/swap.h
include/linux/thermal.h [new file with mode: 0644]
include/linux/tty.h
include/mtd/mtd-abi.h
include/mtd/ubi-header.h
include/mtd/ubi-user.h
init/Kconfig
init/initramfs.c
init/main.c
kernel/Makefile
kernel/cgroup.c
kernel/cpuset.c
kernel/fork.c
kernel/kexec.c
kernel/panic.c
kernel/pid.c
kernel/power/Kconfig
kernel/res_counter.c [new file with mode: 0644]
kernel/sysctl.c
mm/Makefile
mm/bootmem.c
mm/filemap.c
mm/memcontrol.c [new file with mode: 0644]
mm/memory.c
mm/migrate.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/rxrpc/af_rxrpc.c
scripts/kernel-doc
security/keys/key.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c

index 40ac7759c3bb5342edf9168153edbf1f1ff05e79..6e9c4050a41baedb072d0d0ba60d2391c7fd4e88 100644 (file)
@@ -14,6 +14,7 @@ Following translations are available on the WWW:
        - this file.
 ABI/
        - info on kernel <-> userspace ABI and relative interface stability.
+
 BUG-HUNTING
        - brute force method of doing binary search of patches to find bug.
 Changes
@@ -66,6 +67,8 @@ VGA-softcursor.txt
        - how to change your VGA cursor from a blinking underscore.
 accounting/
        - documentation on accounting and taskstats.
+acpi/
+       - info on ACPI-specific hooks in the kernel.
 aoe/
        - description of AoE (ATA over Ethernet) along with config examples.
 applying-patches.txt
@@ -126,18 +129,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 +335,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 +349,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
diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi
new file mode 100644 (file)
index 0000000..9470ed9
--- /dev/null
@@ -0,0 +1,99 @@
+What:          /sys/firmware/acpi/interrupts/
+Date:          February 2008
+Contact:       Len Brown <lenb@kernel.org>
+Description:
+               All ACPI interrupts are handled via a single IRQ,
+               the System Control Interrupt (SCI), which appears
+               as "acpi" in /proc/interrupts.
+
+               However, one of the main functions of ACPI is to make
+               the platform understand random hardware without
+               special driver support.  So while the SCI handles a few
+               well known (fixed feature) interrupts sources, such
+               as the power button, it can also handle a variable
+               number of a "General Purpose Events" (GPE).
+
+               A GPE vectors to a specified handler in AML, which
+               can do a anything the BIOS writer wants from
+               OS context.  GPE 0x12, for example, would vector
+               to a level or edge handler called _L12 or _E12.
+               The handler may do its business and return.
+               Or the handler may send send a Notify event
+               to a Linux device driver registered on an ACPI device,
+               such as a battery, or a processor.
+
+               To figure out where all the SCI's are coming from,
+               /sys/firmware/acpi/interrupts contains a file listing
+               every possible source, and the count of how many
+               times it has triggered.
+
+               $ cd /sys/firmware/acpi/interrupts
+               $ grep . *
+               error:0
+               ff_gbl_lock:0
+               ff_pmtimer:0
+               ff_pwr_btn:0
+               ff_rt_clk:0
+               ff_slp_btn:0
+               gpe00:0
+               gpe01:0
+               gpe02:0
+               gpe03:0
+               gpe04:0
+               gpe05:0
+               gpe06:0
+               gpe07:0
+               gpe08:0
+               gpe09:174
+               gpe0A:0
+               gpe0B:0
+               gpe0C:0
+               gpe0D:0
+               gpe0E:0
+               gpe0F:0
+               gpe10:0
+               gpe11:60
+               gpe12:0
+               gpe13:0
+               gpe14:0
+               gpe15:0
+               gpe16:0
+               gpe17:0
+               gpe18:0
+               gpe19:7
+               gpe1A:0
+               gpe1B:0
+               gpe1C:0
+               gpe1D:0
+               gpe1E:0
+               gpe1F:0
+               gpe_all:241
+               sci:241
+
+               sci - The total number of times the ACPI SCI
+               has claimed an interrupt.
+
+               gpe_all - count of SCI caused by GPEs.
+
+               gpeXX - count for individual GPE source
+
+               ff_gbl_lock - Global Lock
+
+               ff_pmtimer - PM Timer
+
+               ff_pwr_btn - Power Button
+
+               ff_rt_clk - Real Time Clock
+
+               ff_slp_btn - Sleep Button
+
+               error - an interrupt that can't be accounted for above.
+
+               Root has permission to clear any of these counters.  Eg.
+               # echo 0 > gpe11
+
+               All counters can be cleared by clearing the total "sci":
+               # echo 0 > sci
+
+               None of these counters has an effect on the function
+               of the system, they are simply statistics.
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 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 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
diff --git a/Documentation/acpi/dsdt-override.txt b/Documentation/acpi/dsdt-override.txt
new file mode 100644 (file)
index 0000000..5008f25
--- /dev/null
@@ -0,0 +1,15 @@
+Linux supports two methods of overriding the BIOS DSDT:
+
+CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel.
+
+CONFIG_ACPI_CUSTOM_DSDT_INITRD adds the image to the initrd.
+
+When to use these methods is described in detail on the
+Linux/ACPI home page:
+http://www.lesswatts.org/projects/acpi/overridingDSDT.php
+
+Note that if both options are used, the DSDT supplied
+by the INITRD method takes precedence.
+
+Documentation/initramfs-add-dsdt.sh is provided for convenience
+for use with the CONFIG_ACPI_CUSTOM_DSDT_INITRD method.
diff --git a/Documentation/acpi/initramfs-add-dsdt.sh b/Documentation/acpi/initramfs-add-dsdt.sh
new file mode 100755 (executable)
index 0000000..17ef6e8
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Adds a DSDT file to the initrd (if it's an initramfs)
+# first argument is the name of archive
+# second argument is the name of the file to add
+# The file will be copied as /DSDT.aml
+
+# 20060126: fix "Premature end of file" with some old cpio (Roland Robic)
+# 20060205: this time it should really work
+
+# check the arguments
+if [ $# -ne 2 ]; then
+       program_name=$(basename $0)
+       echo "\
+$program_name: too few arguments
+Usage: $program_name initrd-name.img DSDT-to-add.aml
+Adds a DSDT file to an initrd (in initramfs format)
+
+  initrd-name.img: filename of the initrd in initramfs format
+  DSDT-to-add.aml: filename of the DSDT file to add
+  " 1>&2
+    exit 1
+fi
+
+# we should check it's an initramfs
+
+tempcpio=$(mktemp -d)
+# cleanup on exit, hangup, interrupt, quit, termination
+trap 'rm -rf $tempcpio' 0 1 2 3 15
+
+# extract the archive
+gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1
+
+# copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml"
+cp -f "$2" "$tempcpio"/DSDT.aml
+
+# add the file
+cd "$tempcpio"
+(echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1
+cd "$OLDPWD"
+
+# re-compress the archive
+gzip -c "$tempcpio"/initramfs.cpio > "$1"
+
diff --git a/Documentation/acpi/method-tracing.txt b/Documentation/acpi/method-tracing.txt
new file mode 100644 (file)
index 0000000..f6efb1e
--- /dev/null
@@ -0,0 +1,26 @@
+/sys/module/acpi/parameters/:
+
+trace_method_name
+       The AML method name that the user wants to trace
+
+trace_debug_layer
+       The temporary debug_layer used when tracing the method.
+       Using 0xffffffff by default if it is 0.
+
+trace_debug_level
+       The temporary debug_level used when tracing the method.
+       Using 0x00ffffff by default if it is 0.
+
+trace_state
+       The status of the tracing feature.
+
+       "enabled" means this feature is enabled
+       and the AML method is traced every time it's executed.
+
+       "1" means this feature is enabled and the AML method
+       will only be traced during the next execution.
+
+       "disabled" means this feature is disabled.
+       Users can enable/disable this debug tracing feature by
+       "echo string > /sys/module/acpi/parameters/trace_state".
+       "string" should be one of "enable", "disable" and "1".
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,
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 68ce1300a3609f9a5e0061cf61c0a5f3c05f80fe..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
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
similarity index 99%
rename from Documentation/dnotify.txt
rename to Documentation/filesystems/dnotify.txt
index 6984fca6002a304272ea3606e0ad1a34568221d6..9f5d338ddbb8349a6e04ff8c51a6349b44be4034 100644 (file)
@@ -69,24 +69,24 @@ Example
        #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);
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 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 8fd5aa40585ff8419cc730104079ddd61b5ccb8e..0dcbd266b44280188b8b3469d49c4c62b40e6934 100644 (file)
@@ -147,8 +147,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        default: 0
 
        acpi_sleep=     [HW,ACPI] Sleep options
-                       Format: { s3_bios, s3_mode }
-                       See Documentation/power/video.txt
+                       Format: { s3_bios, s3_mode, s3_beep }
+                       See Documentation/power/video.txt for s3_bios and s3_mode.
+                       s3_beep is for debugging; it makes the PC's speaker beep
+                       as soon as the kernel's real-mode entry point is called.
 
        acpi_sci=       [HW,ACPI] ACPI System Control Interrupt trigger mode
                        Format: { level | edge | high | low }
@@ -175,6 +177,9 @@ and is between 256 and 4096 characters. It is defined in the file
 
        acpi_no_auto_ssdt       [HW,ACPI] Disable automatic loading of SSDT
 
+       acpi_no_initrd_override [KNL,ACPI]
+                       Disable loading custom ACPI tables from the initramfs
+
        acpi_os_name=   [HW,ACPI] Tell ACPI BIOS the name of the OS
                        Format: To spoof as Windows 98: ="Microsoft Windows"
 
index 8c35c0426110f149100be9cb2c17921e8e25ae39..56757c751d6fc5611b181f6d79302a195b3fe8c7 100644 (file)
@@ -39,12 +39,33 @@ LED Device Naming
 
 Is currently of the form:
 
-"devicename:colour"
+"devicename:colour:function"
 
 There have been calls for LED properties such as colour to be exported as
 individual led class attributes. As a solution which doesn't incur as much
 overhead, I suggest these become part of the device name. The naming scheme
-above leaves scope for further attributes should they be needed.
+above leaves scope for further attributes should they be needed. If sections
+of the name don't apply, just leave that section blank.
+
+
+Hardware accelerated blink of LEDs
+==================================
+
+Some LEDs can be programmed to blink without any CPU interaction. To
+support this feature, a LED driver can optionally implement the
+blink_set() function (see <linux/leds.h>). If implemeted, triggers can
+attempt to use it before falling back to software timers. The blink_set()
+function should return 0 if the blink setting is supported, or -EINVAL
+otherwise, which means that LED blinking will be handled by software.
+
+The blink_set() function should choose a user friendly blinking
+value if it is called with *delay_on==0 && *delay_off==0 parameters. In
+this case the driver should give back the chosen value through delay_on
+and delay_off parameters to the leds subsystem.
+
+Any call to the brightness_set() callback function should cancel the
+previously programmed hardware blinking function so setting the brightness
+to 0 can also cancel the blinking of the LED.
 
 
 Known Issues
@@ -55,10 +76,6 @@ would cause nightmare dependency issues. I see this as a minor issue
 compared to the benefits the simple trigger functionality brings. The
 rest of the LED subsystem can be modular.
 
-Some leds can be programmed to flash in hardware. As this isn't a generic
-LED device property, this should be exported as a device specific sysfs
-attribute rather than part of the class if this functionality is required.
-
 
 Future Development
 ==================
index aea7e920966753193c6139d84e7839f7de485ebe..9d60ab717a7b3c8dc0daa4d14e6a914884965bf0 100644 (file)
@@ -386,6 +386,11 @@ before suspending; then remount them after resuming.
 There is a work-around for this problem.  For more information, see
 Documentation/usb/persist.txt.
 
+Q: Can I suspend-to-disk using a swap partition under LVM?
+
+A: No. You can suspend successfully, but you'll not be able to
+resume. uswsusp should be able to work with LVM. See suspend.sf.net.
+
 Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
 compiled with the similar configuration files. Anyway I found that
 suspend to disk (and resume) is much slower on 2.6.16 compared to
index b5e46efeba84bd3715cfea3cf5d4c84be6010332..7b4e8a70882c2ff4fb4d61e4bc12a4987a7d06eb 100644 (file)
@@ -57,6 +57,7 @@ Table of Contents
       n) 4xx/Axon EMAC ethernet nodes
       o) Xilinx IP cores
       p) Freescale Synchronous Serial Interface
+         q) USB EHCI controllers
 
   VII - Specifying interrupt information for devices
     1) interrupts property
@@ -2577,6 +2578,20 @@ platforms are moved over to use the flattened-device-tree model.
       Requred properties:
        - current-speed : Baud rate of uartlite
 
+      v) Xilinx hwicap
+
+               Xilinx hwicap devices provide access to the configuration logic
+               of the FPGA through the Internal Configuration Access Port
+               (ICAP).  The ICAP enables partial reconfiguration of the FPGA,
+               readback of the configuration information, and some control over
+               'warm boots' of the FPGA fabric.
+
+               Required properties:
+               - xlnx,family : The family of the FPGA, necessary since the
+                      capabilities of the underlying ICAP hardware
+                      differ between different families.  May be
+                      'virtex2p', 'virtex4', or 'virtex5'.
+
     p) Freescale Synchronous Serial Interface
 
        The SSI is a serial device that communicates with audio codecs.  It can
@@ -2775,6 +2790,33 @@ platforms are moved over to use the flattened-device-tree model.
                interrupt-parent = < &ipic >;
         };
 
+    q) USB EHCI controllers
+
+    Required properties:
+      - compatible : should be "usb-ehci".
+      - reg : should contain at least address and length of the standard EHCI
+        register set for the device. Optional platform-dependent registers
+        (debug-port or other) can be also specified here, but only after
+        definition of standard EHCI registers.
+      - interrupts : one EHCI interrupt should be described here.
+    If device registers are implemented in big endian mode, the device
+    node should have "big-endian-regs" property.
+    If controller implementation operates with big endian descriptors,
+    "big-endian-desc" property should be specified.
+    If both big endian registers and descriptors are used by the controller
+    implementation, "big-endian" property can be specified instead of having
+    both "big-endian-regs" and "big-endian-desc".
+
+     Example (Sequoia 440EPx):
+           ehci@e0000300 {
+                  compatible = "ibm,usb-ehci-440epx", "usb-ehci";
+                  interrupt-parent = <&UIC0>;
+                  interrupts = <1a 4>;
+                  reg = <0 e0000300 90 0 e0000390 70>;
+                  big-endian;
+          };
+
+
    More devices will be defined as this spec matures.
 
 VII - Specifying interrupt information for devices
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).
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/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
new file mode 100644 (file)
index 0000000..5776e09
--- /dev/null
@@ -0,0 +1,246 @@
+Generic Thermal Sysfs driver How To
+=========================
+
+Written by Sujith Thomas <sujith.thomas@intel.com>, Zhang Rui <rui.zhang@intel.com>
+
+Updated: 2 January 2008
+
+Copyright (c)  2008 Intel Corporation
+
+
+0. Introduction
+
+The generic thermal sysfs provides a set of interfaces for thermal zone devices (sensors)
+and thermal cooling devices (fan, processor...) to register with the thermal management
+solution and to be a part of it.
+
+This how-to focusses on enabling new thermal zone and cooling devices to participate
+in thermal management.
+This solution is platform independent and any type of thermal zone devices and
+cooling devices should be able to make use of the infrastructure.
+
+The main task of the thermal sysfs driver is to expose thermal zone attributes as well
+as cooling device attributes to the user space.
+An intelligent thermal management application can make decisions based on inputs
+from thermal zone attributes (the current temperature and trip point temperature)
+and throttle appropriate devices.
+
+[0-*]  denotes any positive number starting from 0
+[1-*]  denotes any positive number starting from 1
+
+1. thermal sysfs driver interface functions
+
+1.1 thermal zone device interface
+1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *name, int trips,
+                               void *devdata, struct thermal_zone_device_ops *ops)
+
+       This interface function adds a new thermal zone device (sensor) to
+       /sys/class/thermal folder as thermal_zone[0-*].
+       It tries to bind all the thermal cooling devices registered at the same time.
+
+       name: the thermal zone name.
+       trips: the total number of trip points this thermal zone supports.
+       devdata: device private data
+       ops: thermal zone device callbacks.
+               .bind: bind the thermal zone device with a thermal cooling device.
+               .unbind: unbing the thermal zone device with a thermal cooling device.
+               .get_temp: get the current temperature of the thermal zone.
+               .get_mode: get the current mode (user/kernel) of the thermal zone.
+                          "kernel" means thermal management is done in kernel.
+                          "user" will prevent kernel thermal driver actions upon trip points
+                          so that user applications can take charge of thermal management.
+               .set_mode: set the mode (user/kernel) of the thermal zone.
+               .get_trip_type: get the type of certain trip point.
+               .get_trip_temp: get the temperature above which the certain trip point
+                               will be fired.
+
+1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz)
+
+       This interface function removes the thermal zone device.
+       It deletes the corresponding entry form /sys/class/thermal folder and unbind all
+       the thermal cooling devices it uses.
+
+1.2 thermal cooling device interface
+1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name,
+                                       void *devdata, struct thermal_cooling_device_ops *)
+
+       This interface function adds a new thermal cooling device (fan/processor/...) to
+       /sys/class/thermal/ folder as cooling_device[0-*].
+       It tries to bind itself to all the thermal zone devices register at the same time.
+       name: the cooling device name.
+       devdata: device private data.
+       ops: thermal cooling devices callbacks.
+               .get_max_state: get the Maximum throttle state of the cooling device.
+               .get_cur_state: get the Current throttle state of the cooling device.
+               .set_cur_state: set the Current throttle state of the cooling device.
+
+1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
+
+       This interface function remove the thermal cooling device.
+       It deletes the corresponding entry form /sys/class/thermal folder and unbind
+       itself from all the thermal zone devices using it.
+
+1.3 interface for binding a thermal zone device with a thermal cooling device
+1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+                       int trip, struct thermal_cooling_device *cdev);
+
+       This interface function bind a thermal cooling device to the certain trip point
+       of a thermal zone device.
+       This function is usually called in the thermal zone device .bind callback.
+       tz: the thermal zone device
+       cdev: thermal cooling device
+       trip: indicates which trip point the cooling devices is associated with
+                in this thermal zone.
+
+1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
+                               int trip, struct thermal_cooling_device *cdev);
+
+       This interface function unbind a thermal cooling device from the certain trip point
+       of a thermal zone device.
+       This function is usually called in the thermal zone device .unbind callback.
+       tz: the thermal zone device
+       cdev: thermal cooling device
+       trip: indicates which trip point the cooling devices is associated with
+               in this thermal zone.
+
+2. sysfs attributes structure
+
+RO     read only value
+RW     read/write value
+
+All thermal sysfs attributes will be represented under /sys/class/thermal
+/sys/class/thermal/
+
+Thermal zone device sys I/F, created once it's registered:
+|thermal_zone[0-*]:
+       |-----type:                     Type of the thermal zone
+       |-----temp:                     Current temperature
+       |-----mode:                     Working mode of the thermal zone
+       |-----trip_point_[0-*]_temp:    Trip point temperature
+       |-----trip_point_[0-*]_type:    Trip point type
+
+Thermal cooling device sys I/F, created once it's registered:
+|cooling_device[0-*]:
+       |-----type :                    Type of the cooling device(processor/fan/...)
+       |-----max_state:                Maximum cooling state of the cooling device
+       |-----cur_state:                Current cooling state of the cooling device
+
+
+These two dynamic attributes are created/removed in pairs.
+They represent the relationship between a thermal zone and its associated cooling device.
+They are created/removed for each
+thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful exection.
+
+|thermal_zone[0-*]
+       |-----cdev[0-*]:                The [0-*]th cooling device in the current thermal zone
+       |-----cdev[0-*]_trip_point:     Trip point that cdev[0-*] is associated with
+
+
+***************************
+* Thermal zone attributes *
+***************************
+
+type                           Strings which represent the thermal zone type.
+                               This is given by thermal zone driver as part of registration.
+                               Eg: "ACPI thermal zone" indicates it's a ACPI thermal device
+                               RO
+                               Optional
+
+temp                           Current temperature as reported by thermal zone (sensor)
+                               Unit: degree celsius
+                               RO
+                               Required
+
+mode                           One of the predifned values in [kernel, user]
+                               This file gives information about the algorithm
+                               that is currently managing the thermal zone.
+                               It can be either default kernel based algorithm
+                               or user space application.
+                               RW
+                               Optional
+                               kernel  = Thermal management in kernel thermal zone driver.
+                               user    = Preventing kernel thermal zone driver actions upon
+                                         trip points so that user application can take full
+                                         charge of the thermal management.
+
+trip_point_[0-*]_temp          The temperature above which trip point will be fired
+                               Unit: degree celsius
+                               RO
+                               Optional
+
+trip_point_[0-*]_type          Strings which indicate the type of the trip point
+                               Eg. it can be one of critical, hot, passive,
+                                   active[0-*] for ACPI thermal zone.
+                               RO
+                               Optional
+
+cdev[0-*]                      Sysfs link to the thermal cooling device node where the sys I/F
+                               for cooling device throttling control represents.
+                               RO
+                               Optional
+
+cdev[0-*]_trip_point           The trip point with which cdev[0-*] is assocated in this thermal zone
+                               -1 means the cooling device is not associated with any trip point.
+                               RO
+                               Optional
+
+******************************
+* Cooling device  attributes *
+******************************
+
+type                           String which represents the type of device
+                               eg: For generic ACPI: this should be "Fan",
+                               "Processor" or "LCD"
+                               eg. For memory controller device on intel_menlow platform:
+                               this should be "Memory controller"
+                               RO
+                               Optional
+
+max_state                      The maximum permissible cooling state of this cooling device.
+                               RO
+                               Required
+
+cur_state                      The current cooling state of this cooling device.
+                               the value can any integer numbers between 0 and max_state,
+                               cur_state == 0 means no cooling
+                               cur_state == max_state means the maximum cooling.
+                               RW
+                               Required
+
+3. A simple implementation
+
+ACPI thermal zone may support multiple trip points like critical/hot/passive/active.
+If an ACPI thermal zone supports critical, passive, active[0] and active[1] at the same time,
+it may register itself as a thermale_zone_device (thermal_zone1) with 4 trip points in all.
+It has one processor and one fan, which are both registered as thermal_cooling_device.
+If the processor is listed in _PSL method, and the fan is listed in _AL0 method,
+the sys I/F structure will be built like this:
+
+/sys/class/thermal:
+
+|thermal_zone1:
+       |-----type:                     ACPI thermal zone
+       |-----temp:                     37
+       |-----mode:                     kernel
+       |-----trip_point_0_temp:        100
+       |-----trip_point_0_type:        critical
+       |-----trip_point_1_temp:        80
+       |-----trip_point_1_type:        passive
+       |-----trip_point_2_temp:        70
+       |-----trip_point_2_type:        active[0]
+       |-----trip_point_3_temp:        60
+       |-----trip_point_3_type:        active[1]
+       |-----cdev0:                    --->/sys/class/thermal/cooling_device0
+       |-----cdev0_trip_point:         1       /* cdev0 can be used for passive */
+       |-----cdev1:                    --->/sys/class/thermal/cooling_device3
+       |-----cdev1_trip_point:         2       /* cdev1 can be used for active[0]*/
+
+|cooling_device0:
+       |-----type:                     Processor
+       |-----max_state:                8
+       |-----cur_state:                0
+
+|cooling_device3:
+       |-----type:                     Fan
+       |-----max_state:                2
+       |-----cur_state:                0
index 10c041ca13c70c8f0e8d9c44a1e3118f34e9d793..6c2477754a2a35025e8c837740693275d2df8f21 100644 (file)
@@ -1,7 +1,7 @@
                     ThinkPad ACPI Extras Driver
 
-                            Version 0.17
-                         October 04th, 2007
+                            Version 0.19
+                         January 06th, 2008
 
                Borislav Deianov <borislav@users.sf.net>
              Henrique de Moraes Holschuh <hmh@hmh.eng.br>
@@ -215,6 +215,11 @@ The following commands can be written to the /proc/acpi/ibm/hotkey file:
        ... any other 8-hex-digit mask ...
        echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
 
+The procfs interface does not support NVRAM polling control.  So as to
+maintain maximum bug-to-bug compatibility, it does not report any masks,
+nor does it allow one to manipulate the hot key mask when the firmware
+does not support masks at all, even if NVRAM polling is in use.
+
 sysfs notes:
 
        hotkey_bios_enabled:
@@ -231,17 +236,26 @@ sysfs notes:
                to this value.
 
        hotkey_enable:
-               Enables/disables the hot keys feature, and reports
-               current status of the hot keys feature.
+               Enables/disables the hot keys feature in the ACPI
+               firmware, and reports current status of the hot keys
+               feature.  Has no effect on the NVRAM hot key polling
+               functionality.
 
                0: disables the hot keys feature / feature disabled
                1: enables the hot keys feature / feature enabled
 
        hotkey_mask:
-               bit mask to enable driver-handling and ACPI event
-               generation for each hot key (see above).  Returns the
-               current status of the hot keys mask, and allows one to
-               modify it.
+               bit mask to enable driver-handling (and depending on
+               the firmware, ACPI event generation) for each hot key
+               (see above).  Returns the current status of the hot keys
+               mask, and allows one to modify it.
+
+               Note: when NVRAM polling is active, the firmware mask
+               will be different from the value returned by
+               hotkey_mask.  The driver will retain enabled bits for
+               hotkeys that are under NVRAM polling even if the
+               firmware refuses them, and will not set these bits on
+               the firmware hot key mask.
 
        hotkey_all_mask:
                bit mask that should enable event reporting for all
@@ -257,12 +271,48 @@ sysfs notes:
                handled by the firmware anyway.  Echo it to
                hotkey_mask above, to use.
 
+       hotkey_source_mask:
+               bit mask that selects which hot keys will the driver
+               poll the NVRAM for.  This is auto-detected by the driver
+               based on the capabilities reported by the ACPI firmware,
+               but it can be overridden at runtime.
+
+               Hot keys whose bits are set in both hotkey_source_mask
+               and also on hotkey_mask are polled for in NVRAM.  Only a
+               few hot keys are available through CMOS NVRAM polling.
+
+               Warning: when in NVRAM mode, the volume up/down/mute
+               keys are synthesized according to changes in the mixer,
+               so you have to use volume up or volume down to unmute,
+               as per the ThinkPad volume mixer user interface.  When
+               in ACPI event mode, volume up/down/mute are reported as
+               separate events, but this behaviour may be corrected in
+               future releases of this driver, in which case the
+               ThinkPad volume mixer user interface semanthics will be
+               enforced.
+
+       hotkey_poll_freq:
+               frequency in Hz for hot key polling. It must be between
+               0 and 25 Hz.  Polling is only carried out when strictly
+               needed.
+
+               Setting hotkey_poll_freq to zero disables polling, and
+               will cause hot key presses that require NVRAM polling
+               to never be reported.
+
+               Setting hotkey_poll_freq too low will cause repeated
+               pressings of the same hot key to be misreported as a
+               single key press, or to not even be detected at all.
+               The recommended polling frequency is 10Hz.
+
        hotkey_radio_sw:
                if the ThinkPad has a hardware radio switch, this
                attribute will read 0 if the switch is in the "radios
                disabled" postition, and 1 if the switch is in the
                "radios enabled" position.
 
+               This attribute has poll()/select() support.
+
        hotkey_report_mode:
                Returns the state of the procfs ACPI event report mode
                filter for hot keys.  If it is set to 1 (the default),
@@ -277,6 +327,25 @@ sysfs notes:
                May return -EPERM (write access locked out by module
                parameter) or -EACCES (read-only).
 
+       wakeup_reason:
+               Set to 1 if the system is waking up because the user
+               requested a bay ejection.  Set to 2 if the system is
+               waking up because the user requested the system to
+               undock.  Set to zero for normal wake-ups or wake-ups
+               due to unknown reasons.
+
+               This attribute has poll()/select() support.
+
+       wakeup_hotunplug_complete:
+               Set to 1 if the system was waken up because of an
+               undock or bay ejection request, and that request
+               was sucessfully completed.  At this point, it might
+               be useful to send the system back to sleep, at the
+               user's choice.  Refer to HKEY events 0x4003 and
+               0x3003, below.
+
+               This attribute has poll()/select() support.
+
 input layer notes:
 
 A Hot key is mapped to a single input layer EV_KEY event, possibly
@@ -427,6 +496,23 @@ Non hot-key ACPI HKEY event map:
 The above events are not propagated by the driver, except for legacy
 compatibility purposes when hotkey_report_mode is set to 1.
 
+0x2304         System is waking up from suspend to undock
+0x2305         System is waking up from suspend to eject bay
+0x2404         System is waking up from hibernation to undock
+0x2405         System is waking up from hibernation to eject bay
+
+The above events are never propagated by the driver.
+
+0x3003         Bay ejection (see 0x2x05) complete, can sleep again
+0x4003         Undocked (see 0x2x04), can sleep again
+0x5009         Tablet swivel: switched to tablet mode
+0x500A         Tablet swivel: switched to normal mode
+0x500B         Tablet pen insterted into its storage bay
+0x500C         Tablet pen removed from its storage bay
+0x5010         Brightness level changed (newer Lenovo BIOSes)
+
+The above events are propagated by the driver.
+
 Compatibility notes:
 
 ibm-acpi and thinkpad-acpi 0.15 (mainline kernels before 2.6.23) never
@@ -1263,3 +1349,17 @@ Sysfs interface changelog:
                and the hwmon class for libsensors4 (lm-sensors 3)
                compatibility.  Moved all hwmon attributes to this
                new platform device.
+
+0x020100:      Marker for thinkpad-acpi with hot key NVRAM polling
+               support.  If you must, use it to know you should not
+               start an userspace NVRAM poller (allows to detect when
+               NVRAM is compiled out by the user because it is
+               unneeded/undesired in the first place).
+0x020101:      Marker for thinkpad-acpi with hot key NVRAM polling
+               and proper hotkey_mask semanthics (version 8 of the
+               NVRAM polling patch).  Some development snapshots of
+               0.18 had an earlier version that did strange things
+               to hotkey_mask.
+
+0x020200:      Add poll()/select() support to the following attributes:
+               hotkey_radio_sw, wakeup_hotunplug_complete, wakeup_reason
index 0885aa2b095a44b3cd66567f80f50aab75ce6d95..aefd23f892bae93d58fed6db9d20b1e601fcea5f 100644 (file)
@@ -202,6 +202,13 @@ L: linux-scsi@vger.kernel.org
 W:     http://www.adaptec.com/
 S:     Supported
 
+ACER WMI LAPTOP EXTRAS
+P:     Carlos Corbacho
+M:     carlos@strangeworlds.co.uk
+L:     aceracpi@googlegroups.com (subscribers-only)
+W:     http://code.google.com/p/aceracpi
+S:     Maintained
+
 ACPI
 P:     Len Brown
 M:     len.brown@intel.com
@@ -252,6 +259,13 @@ L: linux-acpi@vger.kernel.org
 W:     http://acpi.sourceforge.net/
 S:     Supported
 
+ACPI WMI DRIVER
+P:      Carlos Corbacho
+M:      carlos@strangeworlds.co.uk
+L:      linux-acpi@vger.kernel.org
+W:      http://www.lesswatts.org/projects/acpi/
+S:      Maintained
+
 ADM1025 HARDWARE MONITOR DRIVER
 P:     Jean Delvare
 M:     khali@linux-fr.org
@@ -1371,6 +1385,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
@@ -1785,6 +1804,11 @@ P:       Jaroslav Kysela
 M:     perex@perex.cz
 S:     Maintained
 
+HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
+P:     Carlos Corbacho
+M:     carlos@strangeworlds.co.uk
+S:     Odd Fixes
+
 HPET:  High Precision Event Timers driver (hpet.c)
 P:     Clemens Ladisch
 M:     clemens@ladisch.de
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 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 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 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 688659668bdf12156627f7780057ae76c6e9b5fb..8cb07437a807f81d92eed0bbd1a7d82b5118ab5d 100644 (file)
@@ -71,11 +71,11 @@ static struct i2c_board_info __initdata dsmg600_i2c_board_info [] = {
 
 static struct gpio_led dsmg600_led_pins[] = {
        {
-               .name           = "power",
+               .name           = "dsmg600:green:power",
                .gpio           = DSMG600_LED_PWR_GPIO,
        },
        {
-               .name           = "wlan",
+               .name           = "dsmg600:green:wlan",
                .gpio           = DSMG600_LED_WLAN_GPIO,
                .active_low     = true,
        },
index 4cecae84837b37309039280122ed726356d6ab5c..159e1c4f1edaa789deb76336aa1616fd38c02c1c 100644 (file)
@@ -60,17 +60,17 @@ static struct i2c_board_info __initdata nas100d_i2c_board_info [] = {
 
 static struct gpio_led nas100d_led_pins[] = {
        {
-               .name           = "wlan",   /* green led */
+               .name           = "nas100d:green:wlan",
                .gpio           = NAS100D_LED_WLAN_GPIO,
                .active_low     = true,
        },
        {
-               .name           = "power",  /* blue power led (off=flashing) */
+               .name           = "nas100d:blue:power",  /* (off=flashing) */
                .gpio           = NAS100D_LED_PWR_GPIO,
                .active_low     = true,
        },
        {
-               .name           = "disk",   /* yellow led */
+               .name           = "nas100d:yellow:disk",
                .gpio           = NAS100D_LED_DISK_GPIO,
                .active_low     = true,
        },
index acaebcbce53a07319cade57fb80f5bdbb8543ea1..d9a182895a0f998bee850213b0c607dbc13eceb4 100644 (file)
@@ -63,20 +63,20 @@ static struct i2c_board_info __initdata nslu2_i2c_board_info [] = {
 
 static struct gpio_led nslu2_led_pins[] = {
        {
-               .name           = "ready",  /* green led */
+               .name           = "nslu2:green:ready",
                .gpio           = NSLU2_LED_GRN_GPIO,
        },
        {
-               .name           = "status", /* red led */
+               .name           = "nslu2:red:status",
                .gpio           = NSLU2_LED_RED_GPIO,
        },
        {
-               .name           = "disk-1",
+               .name           = "nslu2:green:disk-1",
                .gpio           = NSLU2_LED_DISK1_GPIO,
                .active_low     = true,
        },
        {
-               .name           = "disk-2",
+               .name           = "nslu2:green:disk-2",
                .gpio           = NSLU2_LED_DISK2_GPIO,
                .active_low     = true,
        },
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 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 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 b38ae1fc15fd701728d67e30e37d7370a146a2ce..6c01464db699419a2b5e8068325c1791ad356188 100644 (file)
@@ -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 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 5a216c019924ff22fbce7da38aaebea97da7c732..cbe6cee5a550327500d5497d6c445eb471714a12 100644 (file)
@@ -45,6 +45,12 @@ static void init_intel_pdc(struct acpi_processor *pr)
        buf[0] = ACPI_PDC_REVISION_ID;
        buf[1] = 1;
        buf[2] = ACPI_PDC_EST_CAPABILITY_SMP;
+       /*
+        * The default of PDC_SMP_T_SWCOORD bit is set for IA64 cpu so
+        * that OSPM is capable of native ACPI throttling software
+        * coordination using BIOS supplied _TSD info.
+        */
+       buf[2] |= ACPI_PDC_SMP_T_SWCOORD;
 
        obj->type = ACPI_TYPE_BUFFER;
        obj->buffer.length = 12;
index 00b5d08f6da8d67da2f67c9506d1164e72e7e0a7..78f28d825f30fc7accf50064b97466f4d5bfeaf0 100644 (file)
@@ -69,6 +69,20 @@ unsigned int acpi_cpei_phys_cpuid;
 
 unsigned long acpi_wakeup_address = 0;
 
+#ifdef CONFIG_IA64_GENERIC
+static unsigned long __init acpi_find_rsdp(void)
+{
+       unsigned long rsdp_phys = 0;
+
+       if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
+               rsdp_phys = efi.acpi20;
+       else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
+               printk(KERN_WARNING PREFIX
+                      "v1.0/r0.71 tables no longer supported\n");
+       return rsdp_phys;
+}
+#endif
+
 const char __init *
 acpi_get_sysname(void)
 {
@@ -152,7 +166,7 @@ int acpi_request_vector(u32 int_type)
        return vector;
 }
 
-char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
+char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
 {
        return __va(phys_addr);
 }
@@ -601,8 +615,6 @@ int acpi_register_gsi(u32 gsi, int triggering, int polarity)
                                     IOSAPIC_LEVEL);
 }
 
-EXPORT_SYMBOL(acpi_register_gsi);
-
 void acpi_unregister_gsi(u32 gsi)
 {
        if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM)
@@ -611,8 +623,6 @@ void acpi_unregister_gsi(u32 gsi)
        iosapic_unregister_intr(gsi);
 }
 
-EXPORT_SYMBOL(acpi_unregister_gsi);
-
 static int __init acpi_parse_fadt(struct acpi_table_header *table)
 {
        struct acpi_table_header *fadt_header;
@@ -631,18 +641,6 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
        return 0;
 }
 
-unsigned long __init acpi_find_rsdp(void)
-{
-       unsigned long rsdp_phys = 0;
-
-       if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
-               rsdp_phys = efi.acpi20;
-       else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
-               printk(KERN_WARNING PREFIX
-                      "v1.0/r0.71 tables no longer supported\n");
-       return rsdp_phys;
-}
-
 int __init acpi_boot_init(void)
 {
 
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 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 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 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 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 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 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 cf030b00441507166720db089caf700cd3691181..8dcac0b22d68ba2f77d82329b2b0b55e6700d4a9 100644 (file)
@@ -97,6 +97,7 @@ config EARLY_PRINTK
 config COMPAT
        bool
        default y if PPC64
+       select COMPAT_BINFMT_ELF
 
 config SYSVIPC_COMPAT
        bool
@@ -438,25 +439,6 @@ config WANT_DEVICE_TREE
        bool
        default n
 
-config DEVICE_TREE
-       string "Static device tree source file"
-       depends on WANT_DEVICE_TREE
-       help
-         This specifies the device tree source (.dts) file to be
-         compiled and included when building the bootwrapper.  If a
-         relative filename is given, then it will be relative to
-         arch/powerpc/boot/dts.  If you are not using the bootwrapper,
-         or do not need to build a dts into the bootwrapper, this
-         field is ignored.
-
-         For example, this is required when building a cuImage target
-         for an older U-Boot, which cannot pass a device tree itself.
-         Such a kernel will not work with a newer U-Boot that tries to
-         pass a device tree (unless you tell it not to).  If your U-Boot
-         does not mention a device tree in "help bootm", then use the
-         cuImage target and specify a device tree here.  Otherwise, use
-         the uImage target and leave this field blank.
-
 endmenu
 
 config ISA_DMA_API
@@ -512,7 +494,7 @@ config PCI
        bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
                || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
                || PPC_PS3 || 44x
-       default y if !40x && !CPM2 && !8xx && !PPC_83xx \
+       default y if !40x && !CPM2 && !8xx && !PPC_MPC512x && !PPC_83xx \
                && !PPC_85xx && !PPC_86xx
        default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
        default PCI_QSPAN if !4xx && !CPM2 && 8xx
index f70df9b64f8f601c420e857d0fba4a4f9b85276d..6845482f009354e531ede0d90cb5a6dde20c7c07 100644 (file)
@@ -151,14 +151,11 @@ core-$(CONFIG_XMON)               += arch/powerpc/xmon/
 drivers-$(CONFIG_OPROFILE)     += arch/powerpc/oprofile/
 
 # Default to zImage, override when needed
-defaultimage-y                 := zImage
-defaultimage-$(CONFIG_DEFAULT_UIMAGE) := uImage
-KBUILD_IMAGE := $(defaultimage-y)
-all: $(KBUILD_IMAGE)
+all: zImage
 
 CPPFLAGS_vmlinux.lds   := -Upowerpc
 
-BOOT_TARGETS = zImage zImage.initrd uImage
+BOOT_TARGETS = zImage zImage.initrd uImage treeImage.% cuImage.%
 
 PHONY += $(BOOT_TARGETS)
 
@@ -180,7 +177,7 @@ define archhelp
 endef
 
 install: vdso_install
-       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
+       $(Q)$(MAKE) $(build)=$(boot) install
 
 vdso_install:
 ifeq ($(CONFIG_PPC64),y)
index 122a27078998e817931fb9a92d4e1950eb414bd9..49797a45416c8ce441c3255ae2b0ce41a9989dbb 100644 (file)
@@ -60,8 +60,9 @@ src-wlib := string.S crt0.S stdio.c main.c \
 src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \
                cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
                ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
-               cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \
-               fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c cuboot-taishan.c \
+               cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \
+               cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \
+               fixed-head.S ep88xc.c ep405.c \
                cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \
                cuboot-warp.c cuboot-85xx-cpm2.c
 src-boot := $(src-wlib) $(src-plat) empty.c
@@ -123,6 +124,8 @@ targets             += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a)
 extra-y                := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
                   $(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds
 
+dtstree                := $(srctree)/$(src)/dts
+
 wrapper                :=$(srctree)/$(src)/wrapper
 wrapperbits    := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc) \
                        $(wrapper) FORCE
@@ -181,7 +184,7 @@ quiet_cmd_wrap      = WRAP    $@
 image-$(CONFIG_PPC_PSERIES)            += zImage.pseries
 image-$(CONFIG_PPC_MAPLE)              += zImage.pseries
 image-$(CONFIG_PPC_IBM_CELL_BLADE)     += zImage.pseries
-image-$(CONFIG_PPC_PS3)                        += zImage.ps3
+image-$(CONFIG_PPC_PS3)                        += zImage-dtb.ps3
 image-$(CONFIG_PPC_CELLEB)             += zImage.pseries
 image-$(CONFIG_PPC_CHRP)               += zImage.chrp
 image-$(CONFIG_PPC_EFIKA)              += zImage.chrp
@@ -191,33 +194,69 @@ image-$(CONFIG_PPC_PRPMC2800)             += zImage.prpmc2800
 image-$(CONFIG_PPC_ISERIES)            += zImage.iseries
 image-$(CONFIG_DEFAULT_UIMAGE)         += uImage
 
-ifneq ($(CONFIG_DEVICE_TREE),"")
-image-$(CONFIG_PPC_8xx)                        += cuImage.8xx
-image-$(CONFIG_PPC_EP88XC)             += zImage.ep88xc
-image-$(CONFIG_EP405)                  += zImage.ep405
-image-$(CONFIG_8260)                   += cuImage.pq2
-image-$(CONFIG_EP8248E)                        += zImage.ep8248e
-image-$(CONFIG_PPC_MPC52xx)            += cuImage.52xx
-image-$(CONFIG_STORCENTER)             += cuImage.824x
-image-$(CONFIG_PPC_83xx)               += cuImage.83xx
-image-$(CONFIG_PPC_85xx)               += cuImage.85xx
-ifeq ($(CONFIG_CPM2),y)
-image-$(CONFIG_PPC_85xx)               += cuImage.85xx-cpm2
-endif
-image-$(CONFIG_MPC7448HPC2)            += cuImage.hpc2
+#
+# Targets which embed a device tree blob
+#
+# Theses are default targets to build images which embed device tree blobs.
+# They are only required on boards which do not have FDT support in firmware.
+# Boards with newish u-boot firmare can use the uImage target above
+#
+
+# Board ports in arch/powerpc/platform/40x/Kconfig
+image-$(CONFIG_EP405)                  += zImage-dtb.ep405
+image-$(CONFIG_WALNUT)                 += treeImage.walnut
+
+# Board ports in arch/powerpc/platform/44x/Kconfig
 image-$(CONFIG_EBONY)                  += treeImage.ebony cuImage.ebony
 image-$(CONFIG_BAMBOO)                 += treeImage.bamboo cuImage.bamboo
 image-$(CONFIG_SEQUOIA)                        += cuImage.sequoia
 image-$(CONFIG_RAINIER)                        += cuImage.rainier
-image-$(CONFIG_WALNUT)                 += treeImage.walnut
 image-$(CONFIG_TAISHAN)                        += cuImage.taishan
 image-$(CONFIG_KATMAI)                 += cuImage.katmai
 image-$(CONFIG_WARP)                   += cuImage.warp
-endif
 
-ifneq ($(CONFIG_REDBOOT),"")
-image-$(CONFIG_PPC_8xx)                        += zImage.redboot-8xx
-endif
+# Board ports in arch/powerpc/platform/8xx/Kconfig
+image-$(CONFIG_PPC_MPC86XADS)          += cuImage.mpc866ads
+image-$(CONFIG_PPC_MPC885ADS)          += cuImage.mpc885ads
+image-$(CONFIG_PPC_EP88XC)             += zImage-dtb.ep88xc
+image-$(CONFIG_PPC_ADDER875)           += cuImage.adder875-uboot \
+                                          zImage-dtb.adder875-redboot
+
+# Board ports in arch/powerpc/platform/52xx/Kconfig
+image-$(CONFIG_PPC_LITE5200)           += cuImage.lite5200 cuImage.lite5200b
+
+# Board ports in arch/powerpc/platform/82xx/Kconfig
+image-$(CONFIG_MPC8272_ADS)            += cuImage.mpc8272ads
+image-$(CONFIG_PQ2FADS)                        += cuImage.pq2fads
+image-$(CONFIG_EP8248E)                        += zImage-dtb.ep8248e
+
+# Board ports in arch/powerpc/platform/83xx/Kconfig
+image-$(CONFIG_MPC832x_MDS)            += cuImage.mpc832x_mds
+image-$(CONFIG_MPC832x_RDB)            += cuImage.mpc832x_rdb
+image-$(CONFIG_MPC834x_ITX)            += cuImage.mpc8349emitx \
+                                          cuImage.mpc8349emitxgp
+image-$(CONFIG_MPC834x_MDS)            += cuImage.mpc834x_mds
+image-$(CONFIG_MPC836x_MDS)            += cuImage.mpc836x_mds
+
+# Board ports in arch/powerpc/platform/85xx/Kconfig
+image-$(CONFIG_MPC8540_ADS)            += cuImage.mpc8540ads
+image-$(CONFIG_MPC8560_ADS)            += cuImage.mpc8560ads
+image-$(CONFIG_MPC85xx_CDS)            += cuImage.mpc8541cds \
+                                          cuImage.mpc8548cds \
+                                          cuImage.mpc8555cds
+image-$(CONFIG_MPC85xx_MDS)            += cuImage.mpc8568mds
+image-$(CONFIG_MPC85xx_DS)             += cuImage.mpc8544ds \
+                                          cuImage.mpc8572ds
+image-$(CONFIG_TQM8540)                        += cuImage.tqm8540
+image-$(CONFIG_TQM8541)                        += cuImage.tqm8541
+image-$(CONFIG_TQM8555)                        += cuImage.tqm8555
+image-$(CONFIG_TQM8560)                        += cuImage.tqm8560
+image-$(CONFIG_SBC8548)                        += cuImage.tqm8548
+image-$(CONFIG_SBC8560)                        += cuImage.tqm8560
+
+# Board ports in arch/powerpc/platform/embedded6xx/Kconfig
+image-$(CONFIG_STORCENTER)             += cuImage.storcenter
+image-$(CONFIG_MPC7448HPC2)            += cuImage.mpc7448hpc2
 
 # For 32-bit powermacs, build the COFF and miboot images
 # as well as the ELF images.
@@ -233,24 +272,20 @@ targets   += $(image-y) $(initrd-y)
 
 $(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
 
-# If CONFIG_WANT_DEVICE_TREE is set and CONFIG_DEVICE_TREE isn't an
-# empty string, define 'dts' to be path to the dts
-# CONFIG_DEVICE_TREE will have "" around it, make sure to strip them
-ifeq ($(CONFIG_WANT_DEVICE_TREE),y)
-ifneq ($(CONFIG_DEVICE_TREE),"")
-dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\
-       ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE:"%"=%)
-endif
-endif
-
 # Don't put the ramdisk on the pattern rule; when its missing make will try
 # the pattern rule with less dependencies that also matches (even with the
 # hard dependency listed).
-$(obj)/zImage.initrd.%: vmlinux $(wrapperbits) $(dts)
-       $(call if_changed,wrap,$*,$(dts),,$(obj)/ramdisk.image.gz)
+$(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
+       $(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
 
-$(obj)/zImage.%: vmlinux $(wrapperbits) $(dts)
-       $(call if_changed,wrap,$*,$(dts))
+$(obj)/zImage.%: vmlinux $(wrapperbits)
+       $(call if_changed,wrap,$*)
+
+$(obj)/zImage-dtb.initrd.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
+       $(call if_changed,wrap,$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz)
+
+$(obj)/zImage-dtb.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
+       $(call if_changed,wrap,$*,$(dtstree)/$*.dts)
 
 # This cannot be in the root of $(src) as the zImage rule always adds a $(obj)
 # prefix
@@ -260,24 +295,17 @@ $(obj)/vmlinux.strip: vmlinux
 $(obj)/zImage.iseries: vmlinux
        $(STRIP) -s -R .comment $< -o $@
 
-$(obj)/zImage.ps3: vmlinux  $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts
-       $(STRIP) -s -R .comment $< -o vmlinux.strip
-       $(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,)
-
-$(obj)/zImage.initrd.ps3: vmlinux  $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts $(obj)/ramdisk.image.gz
-       $(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,$(obj)/ramdisk.image.gz)
-
 $(obj)/uImage: vmlinux $(wrapperbits)
        $(call if_changed,wrap,uboot)
 
-$(obj)/cuImage.%: vmlinux $(dts) $(wrapperbits)
-       $(call if_changed,wrap,cuboot-$*,$(dts))
+$(obj)/cuImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
+       $(call if_changed,wrap,cuboot-$*,$(dtstree)/$*.dts)
 
-$(obj)/treeImage.initrd.%: vmlinux $(dts) $(wrapperbits)
-       $(call if_changed,wrap,treeboot-$*,$(dts),,$(obj)/ramdisk.image.gz)
+$(obj)/treeImage.initrd.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
+       $(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz)
 
-$(obj)/treeImage.%: vmlinux $(dts) $(wrapperbits)
-       $(call if_changed,wrap,treeboot-$*,$(dts))
+$(obj)/treeImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
+       $(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts)
 
 # If there isn't a platform selected then just strip the vmlinux.
 ifeq (,$(image-y))
index 930bfb3894ebbf862966ea8629e583e89d0e15e3..28e9cd3d7a216c841ee8b8c6bd119b6194bed2cb 100644 (file)
                                compatible = "fsl,mpc875-brg",
                                             "fsl,cpm1-brg",
                                             "fsl,cpm-brg";
+                               clock-frequency = <50000000>;
                                reg = <0x9f0 0x10>;
                        };
 
index 0197242dacfb08945d2eb1ccb77520f819635434..54fb60ec03e540c06a37556f4535aa19c13ce959 100644 (file)
                                compatible = "fsl,mpc875-brg",
                                             "fsl,cpm1-brg",
                                             "fsl,cpm-brg";
+                               clock-frequency = <50000000>;
                                reg = <0x9f0 0x10>;
                        };
 
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
new file mode 100644 (file)
index 0000000..94ad7b2
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * MPC5121E MDS Device Tree Source
+ *
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "mpc5121ads";
+       compatible = "fsl,mpc5121ads";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,5121@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <0x20>;     // 32 bytes
+                       i-cache-line-size = <0x20>;     // 32 bytes
+                       d-cache-size = <0x8000>;        // L1, 32K
+                       i-cache-size = <0x8000>;        // L1, 32K
+                       timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
+                       bus-frequency = <198000000>;    // 198 MHz csb bus
+                       clock-frequency = <396000000>;  // 396 MHz ppc core
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x10000000>;  // 256MB at 0
+       };
+
+       localbus@80000020 {
+               compatible = "fsl,mpc5121ads-localbus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <0x80000020 0x40>;
+
+               ranges = <0x0 0x0 0xfc000000 0x04000000
+                         0x2 0x0 0x82000000 0x00008000>;
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0x0 0x4000000>;
+                       bank-width = <4>;
+                       device-width = <1>;
+               };
+
+               board-control@2,0 {
+                       compatible = "fsl,mpc5121ads-cpld";
+                       reg = <0x2 0x0 0x8000>;
+               };
+       };
+
+       soc@80000000 {
+               compatible = "fsl,mpc5121-immr";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               ranges = <0x0 0x80000000 0x400000>;
+               reg = <0x80000000 0x400000>;
+               bus-frequency = <66000000>;     // 66 MHz ips bus
+
+
+               // IPIC
+               // interrupts cell = <intr #, sense>
+               // sense values match linux IORESOURCE_IRQ_* defines:
+               // sense == 8: Level, low assertion
+               // sense == 2: Edge, high-to-low change
+               //
+               ipic: interrupt-controller@c00 {
+                       compatible = "fsl,mpc5121-ipic", "fsl,ipic";
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0xc00 0x100>;
+               };
+
+               // 512x PSCs are not 52xx PSCs compatible
+               // PSC3 serial port A aka ttyPSC0
+               serial@11300 {
+                       device_type = "serial";
+                       compatible = "fsl,mpc5121-psc-uart";
+                       // Logical port assignment needed until driver
+                       // learns to use aliases
+                       port-number = <0>;
+                       cell-index = <3>;
+                       reg = <0x11300 0x100>;
+                       interrupts = <0x28 0x8>; // actually the fifo irq
+                       interrupt-parent = < &ipic >;
+               };
+
+               // PSC4 serial port B aka ttyPSC1
+               serial@11400 {
+                       device_type = "serial";
+                       compatible = "fsl,mpc5121-psc-uart";
+                       // Logical port assignment needed until driver
+                       // learns to use aliases
+                       port-number = <1>;
+                       cell-index = <4>;
+                       reg = <0x11400 0x100>;
+                       interrupts = <0x28 0x8>; // actually the fifo irq
+                       interrupt-parent = < &ipic >;
+               };
+
+               pscsfifo@11f00 {
+                       compatible = "fsl,mpc5121-psc-fifo";
+                       reg = <0x11f00 0x100>;
+                       interrupts = <0x28 0x8>;
+                       interrupt-parent = < &ipic >;
+               };
+       };
+};
index 2d6653fe72ff578f91ead0ec74dbd46b7f8d1e05..e1f0dca8ac397324876f46aee281c08a2acc5e39 100644 (file)
                        interrupts = <14 0x8>;
                        interrupt-parent = <&ipic>;
                        dfsrr;
+                       rtc@68 {
+                               compatible = "dallas,ds1339";
+                               reg = <0x68>;
+                       };
                };
 
                i2c@3100 {
index b582032ba3d689fe3a7bba15c488b7d926de3ac9..d7a1ececa30f43fa7486e1669c869c8fdf224a70 100644 (file)
@@ -96,7 +96,7 @@
                #address-cells = <1>;
                #size-cells = <1>;
                device_type = "soc";
-               compatible = "simple-bus";
+               compatible = "fsl,mpc8315-immr", "simple-bus";
                ranges = <0 0xe0000000 0x00100000>;
                reg = <0xe0000000 0x00000200>;
                bus-frequency = <0>;
index 7480edae85edb46149110a9ab75afa57081efaa9..0199c5c548d80a5dfcfa843da5ad929b41a3ed1f 100644 (file)
                                 0xc000 0x0 0x0 0x3 &ipic 23 0x8
                                 0xc000 0x0 0x0 0x4 &ipic 20 0x8>;
                interrupt-parent = <&ipic>;
-               interrupts = <66 0x8>;
+               interrupts = <67 0x8>;
                bus-range = <0 0>;
                ranges = <0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000
                          0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
index 813c259abbe5ca2f0b63477fd54e8787fc931f1b..db37214aee37a0851bbacffe70f64e565608c3f9 100644 (file)
                        bus-frequency = <0>;
                        clock-frequency = <0>;
                };
+
+               PowerPC,8572@1 {
+                       device_type = "cpu";
+                       reg = <1>;
+                       d-cache-line-size = <20>;       // 32 bytes
+                       i-cache-line-size = <20>;       // 32 bytes
+                       d-cache-size = <8000>;          // L1, 32K
+                       i-cache-size = <8000>;          // L1, 32K
+                       timebase-frequency = <0>;
+                       bus-frequency = <0>;
+                       clock-frequency = <0>;
+               };
        };
 
        memory {
index 8848e637293e64244cf629ce11220202569dd997..d84a012c2aaf10340daa1d6c9c24d67070b0a21c 100644 (file)
                                compatible = "fsl,mpc885-brg",
                                             "fsl,cpm1-brg",
                                             "fsl,cpm-brg";
+                               clock-frequency = <0>;
                                reg = <9f0 10>;
                        };
 
index d9046c1adcbea00571d9a5789f371169c217f7ea..5c13d46f441dc3dd7541ee56c1ab6d975bc41abd 100644 (file)
                        interrupts = <15 8>;
                };
 
+               USB0: ehci@e0000300 {
+                       compatible = "ibm,usb-ehci-440epx", "usb-ehci";
+                       interrupt-parent = <&UIC0>;
+                       interrupts = <1a 4>;
+                       reg = <0 e0000300 90 0 e0000390 70>;
+                       big-endian;
+               };
+
                POB0: opb {
                        compatible = "ibm,opb-440epx", "ibm,opb";
                        #address-cells = <1>;
index 2204874ac5f3e5026d123d3a5bbd52530879dac2..5893816c0bcecc5b18ec1653c1cbb2e5c3cc8c1c 100644 (file)
@@ -15,7 +15,7 @@
 
 / {
        model = "StorCenter";
-       compatible = "storcenter";
+       compatible = "iomega,storcenter";
        #address-cells = <1>;
        #size-cells = <1>;
 
                        #size-cells = <0>;
                        compatible = "fsl-i2c";
                        reg = <0x3000 0x100>;
-                       interrupts = <5 2>;
+                       interrupts = <17 2>;
                        interrupt-parent = <&mpic>;
 
                        rtc@68 {
                                compatible = "dallas,ds1337";
-                               reg = <68>;
+                               reg = <0x68>;
                        };
                };
 
@@ -78,7 +78,7 @@
                        reg = <0x4500 0x20>;
                        clock-frequency = <97553800>; /* Hz */
                        current-speed = <115200>;
-                       interrupts = <9 2>;
+                       interrupts = <25 2>;
                        interrupt-parent = <&mpic>;
                };
 
@@ -89,7 +89,7 @@
                        reg = <0x4600 0x20>;
                        clock-frequency = <97553800>; /* Hz */
                        current-speed = <9600>;
-                       interrupts = <10 2>;
+                       interrupts = <26 2>;
                        interrupt-parent = <&mpic>;
                };
 
        };
 
        chosen {
-               linux,stdout-path = "/soc/serial@4500";
+               linux,stdout-path = &serial0;
        };
 };
index 763a0c46f44128ef780dbb6a16ea22c98f70b88b..c3178155311ba1f565e8af685f61f83046b02db1 100755 (executable)
@@ -158,6 +158,29 @@ miboot|uboot)
 cuboot*)
     binary=y
     gzip=
+    case "$platform" in
+    *-mpc885ads|*-adder875*|*-ep88xc)
+        platformo=$object/cuboot-8xx.o
+        ;;
+    *5200*|*-motionpro)
+        platformo=$object/cuboot-52xx.o
+        ;;
+    *-pq2fads|*-ep8248e|*-mpc8272*|*-storcenter)
+        platformo=$object/cuboot-pq2.o
+        ;;
+    *-mpc824*)
+        platformo=$object/cuboot-824x.o
+        ;;
+    *-mpc83*)
+        platformo=$object/cuboot-83xx.o
+        ;;
+    *-tqm8541|*-mpc8560*|*-tqm8560|*-tqm8555*)
+        platformo=$object/cuboot-85xx-cpm2.o
+        ;;
+    *-mpc85*)
+        platformo=$object/cuboot-85xx.o
+        ;;
+    esac
     ;;
 ps3)
     platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o"
index 31bdbf3f7566f8d09627953a96b49efa4d96fc48..a9807f083bc499e16e5bf1c8ab4b4a6f3050f0a4 100644 (file)
@@ -186,7 +186,7 @@ CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_MATH_EMULATION is not set
+CONFIG_MATH_EMULATION=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
@@ -416,14 +416,14 @@ CONFIG_PHYLIB=y
 # MII PHY device drivers
 #
 CONFIG_MARVELL_PHY=y
-# CONFIG_DAVICOM_PHY is not set
+CONFIG_DAVICOM_PHY=y
 # CONFIG_QSEMI_PHY is not set
 # CONFIG_LXT_PHY is not set
 # CONFIG_CICADA_PHY is not set
-# CONFIG_VITESSE_PHY is not set
+CONFIG_VITESSE_PHY=y
 # CONFIG_SMSC_PHY is not set
 # CONFIG_BROADCOM_PHY is not set
-# CONFIG_ICPLUS_PHY is not set
+CONFIG_ICPLUS_PHY=y
 # CONFIG_FIXED_PHY is not set
 # CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
@@ -436,7 +436,7 @@ CONFIG_MII=y
 CONFIG_NETDEV_1000=y
 CONFIG_GIANFAR=y
 # CONFIG_GFAR_NAPI is not set
-# CONFIG_UCC_GETH is not set
+CONFIG_UCC_GETH=y
 CONFIG_NETDEV_10000=y
 
 #
index 58dbfeff9b4da46b51e1db726e9fefae1cb53f20..0662ae46f7246321d865be8a92239679f1837d06 100644 (file)
@@ -2,6 +2,8 @@
 # Makefile for the linux kernel.
 #
 
+CFLAGS_ptrace.o                += -DUTS_MACHINE='"$(UTS_MACHINE)"'
+
 ifeq ($(CONFIG_PPC64),y)
 CFLAGS_prom_init.o     += -mno-minimal-toc
 endif
@@ -15,7 +17,7 @@ obj-y                         := semaphore.o cputable.o ptrace.o syscalls.o \
                                   init_task.o process.o systbl.o idle.o \
                                   signal.o
 obj-y                          += vdso32/
-obj-$(CONFIG_PPC64)            += setup_64.o binfmt_elf32.o sys_ppc32.o \
+obj-$(CONFIG_PPC64)            += setup_64.o sys_ppc32.o \
                                   signal_64.o ptrace32.o \
                                   paca.o cpu_setup_ppc970.o \
                                   cpu_setup_pa6t.o \
index ed083feaf6f9763df72e9458d40552c4927ba611..e6e49289f7882dd11494d9208168e253f806de21 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/suspend.h>
+#include <linux/hrtimer.h>
 #ifdef CONFIG_PPC64
 #include <linux/time.h>
 #include <linux/hardirq.h>
@@ -312,7 +313,7 @@ int main(void)
        DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
        DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
        DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
-       DEFINE(CLOCK_REALTIME_RES, TICK_NSEC);
+       DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64);
 
 #ifdef CONFIG_BUG
        DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
diff --git a/arch/powerpc/kernel/binfmt_elf32.c b/arch/powerpc/kernel/binfmt_elf32.c
deleted file mode 100644 (file)
index 1d45d77..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * binfmt_elf32.c: Support 32-bit PPC ELF binaries on Power3 and followons.
- * based on the SPARC64 version.
- * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller        (davem@redhat.com)
- * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek  (jj@ultra.linux.cz)
- *
- * Copyright (C) 2000,2001 Ken Aaker (kdaaker@rchland.vnet.ibm.com), IBM Corp
- * Copyright (C) 2001 Anton Blanchard (anton@au.ibm.com), IBM
- *
- * 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 <asm/processor.h>
-#include <linux/module.h>
-#include <linux/compat.h>
-#include <linux/elfcore-compat.h>
-
-#undef ELF_ARCH
-#undef ELF_CLASS
-#define ELF_CLASS      ELFCLASS32
-#define ELF_ARCH       EM_PPC
-
-#undef elfhdr
-#undef elf_phdr
-#undef elf_note
-#undef elf_addr_t
-#define elfhdr         elf32_hdr
-#define elf_phdr       elf32_phdr
-#define elf_note       elf32_note
-#define elf_addr_t     Elf32_Off
-
-#define elf_prstatus   compat_elf_prstatus
-#define elf_prpsinfo   compat_elf_prpsinfo
-
-#define elf_core_copy_regs compat_elf_core_copy_regs
-static inline void compat_elf_core_copy_regs(compat_elf_gregset_t *elf_regs,
-                                            struct pt_regs *regs)
-{
-       PPC_ELF_CORE_COPY_REGS((*elf_regs), regs);
-}
-
-#define elf_core_copy_task_regs compat_elf_core_copy_task_regs
-static int compat_elf_core_copy_task_regs(struct task_struct *tsk,
-                                         compat_elf_gregset_t *elf_regs)
-{
-       struct pt_regs *regs = tsk->thread.regs;
-       if (regs)
-               compat_elf_core_copy_regs(elf_regs, regs);
-       return 1;
-}
-
-#include <linux/time.h>
-
-#undef cputime_to_timeval
-#define cputime_to_timeval cputime_to_compat_timeval
-static __inline__ void
-cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
-{
-       unsigned long jiffies = cputime_to_jiffies(cputime);
-       value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
-       value->tv_sec = jiffies / HZ;
-}
-
-#define init_elf_binfmt init_elf32_binfmt
-
-#include "../../../fs/binfmt_elf.c"
index a4c2771b5e6282b9264e4b038c9192a1ccfafc64..2a8f5cc5184f0c02641b7ba78aad7ba3c95367c4 100644 (file)
@@ -959,6 +959,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .cpu_setup              = __setup_cpu_603,
+               .num_pmcs               = 4,
+               .oprofile_cpu_type      = "ppc/e300",
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .platform               = "ppc603",
        },
        {       /* e300c4 (e300c1, plus one IU) */
@@ -971,6 +974,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .dcache_bsize           = 32,
                .cpu_setup              = __setup_cpu_603,
                .machine_check          = machine_check_generic,
+               .num_pmcs               = 4,
+               .oprofile_cpu_type      = "ppc/e300",
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .platform               = "ppc603",
        },
        {       /* default match, we assume split I/D cache & TB (non-601)... */
@@ -1435,7 +1441,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
                .oprofile_cpu_type      = "ppc/e500",
-               .oprofile_type          = PPC_OPROFILE_BOOKE,
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .machine_check          = machine_check_e500,
                .platform               = "ppc8540",
        },
@@ -1453,7 +1459,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
                .oprofile_cpu_type      = "ppc/e500",
-               .oprofile_type          = PPC_OPROFILE_BOOKE,
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .machine_check          = machine_check_e500,
                .platform               = "ppc8548",
        },
index 76b862bd1fe9aab628afabc4180b120040b3b7a8..61dd17449ddceb06267babf5373505984f7abd9c 100644 (file)
@@ -36,7 +36,8 @@ static struct legacy_serial_info {
 static struct __initdata of_device_id parents[] = {
        {.type = "soc",},
        {.type = "tsi-bridge",},
-       {.type = "opb", .compatible = "ibm,opb",},
+       {.type = "opb", },
+       {.compatible = "ibm,opb",},
        {.compatible = "simple-bus",},
        {.compatible = "wrs,epld-localbus",},
 };
index ea04e0ab3f2f192cf4355d27a31f46180aced233..0516e2d3e02ea5b1807d2b17e5ed148118d6535c 100644 (file)
@@ -26,7 +26,7 @@
 
 static void dummy_perf(struct pt_regs *regs)
 {
-#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200)
+#if defined(CONFIG_FSL_EMB_PERFMON)
        mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE);
 #elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
        if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
index 8b056d2295cc07ed4f4403e4683fe4cc17734f8b..7673e98657330dd7f90dd4d29f569d4ea2ca10e8 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/smp.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/signal.h>
 #define PT_MAX_PUT_REG PT_CCR
 #endif
 
+static unsigned long get_user_msr(struct task_struct *task)
+{
+       return task->thread.regs->msr | task->thread.fpexc_mode;
+}
+
+static int set_user_msr(struct task_struct *task, unsigned long msr)
+{
+       task->thread.regs->msr &= ~MSR_DEBUGCHANGE;
+       task->thread.regs->msr |= msr & MSR_DEBUGCHANGE;
+       return 0;
+}
+
+/*
+ * We prevent mucking around with the reserved area of trap
+ * which are used internally by the kernel.
+ */
+static int set_user_trap(struct task_struct *task, unsigned long trap)
+{
+       task->thread.regs->trap = trap & 0xfff0;
+       return 0;
+}
+
 /*
  * Get contents of register REGNO in task TASK.
  */
 unsigned long ptrace_get_reg(struct task_struct *task, int regno)
 {
-       unsigned long tmp = 0;
-
        if (task->thread.regs == NULL)
                return -EIO;
 
-       if (regno == PT_MSR) {
-               tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
-               return tmp | task->thread.fpexc_mode;
-       }
+       if (regno == PT_MSR)
+               return get_user_msr(task);
 
        if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
                return ((unsigned long *)task->thread.regs)[regno];
@@ -87,40 +107,134 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
        if (task->thread.regs == NULL)
                return -EIO;
 
-       if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
-               if (regno == PT_MSR)
-                       data = (data & MSR_DEBUGCHANGE)
-                               | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
-               /* We prevent mucking around with the reserved area of trap
-                * which are used internally by the kernel
-                */
-               if (regno == PT_TRAP)
-                       data &= 0xfff0;
+       if (regno == PT_MSR)
+               return set_user_msr(task, data);
+       if (regno == PT_TRAP)
+               return set_user_trap(task, data);
+
+       if (regno <= PT_MAX_PUT_REG) {
                ((unsigned long *)task->thread.regs)[regno] = data;
                return 0;
        }
        return -EIO;
 }
 
+static int gpr_get(struct task_struct *target, const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       if (target->thread.regs == NULL)
+               return -EIO;
+
+       CHECK_FULL_REGS(target->thread.regs);
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 target->thread.regs,
+                                 0, offsetof(struct pt_regs, msr));
+       if (!ret) {
+               unsigned long msr = get_user_msr(target);
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
+                                         offsetof(struct pt_regs, msr),
+                                         offsetof(struct pt_regs, msr) +
+                                         sizeof(msr));
+       }
+
+       BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
+                    offsetof(struct pt_regs, msr) + sizeof(long));
+
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         &target->thread.regs->orig_gpr3,
+                                         offsetof(struct pt_regs, orig_gpr3),
+                                         sizeof(struct pt_regs));
+       if (!ret)
+               ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                              sizeof(struct pt_regs), -1);
+
+       return ret;
+}
+
+static int gpr_set(struct task_struct *target, const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
+{
+       unsigned long reg;
+       int ret;
+
+       if (target->thread.regs == NULL)
+               return -EIO;
+
+       CHECK_FULL_REGS(target->thread.regs);
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                target->thread.regs,
+                                0, PT_MSR * sizeof(reg));
 
-static int get_fpregs(void __user *data, struct task_struct *task,
-                     int has_fpscr)
+       if (!ret && count > 0) {
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
+                                        PT_MSR * sizeof(reg),
+                                        (PT_MSR + 1) * sizeof(reg));
+               if (!ret)
+                       ret = set_user_msr(target, reg);
+       }
+
+       BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
+                    offsetof(struct pt_regs, msr) + sizeof(long));
+
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                        &target->thread.regs->orig_gpr3,
+                                        PT_ORIG_R3 * sizeof(reg),
+                                        (PT_MAX_PUT_REG + 1) * sizeof(reg));
+
+       if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
+               ret = user_regset_copyin_ignore(
+                       &pos, &count, &kbuf, &ubuf,
+                       (PT_MAX_PUT_REG + 1) * sizeof(reg),
+                       PT_TRAP * sizeof(reg));
+
+       if (!ret && count > 0) {
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
+                                        PT_TRAP * sizeof(reg),
+                                        (PT_TRAP + 1) * sizeof(reg));
+               if (!ret)
+                       ret = set_user_trap(target, reg);
+       }
+
+       if (!ret)
+               ret = user_regset_copyin_ignore(
+                       &pos, &count, &kbuf, &ubuf,
+                       (PT_TRAP + 1) * sizeof(reg), -1);
+
+       return ret;
+}
+
+static int fpr_get(struct task_struct *target, const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
 {
-       unsigned int count = has_fpscr ? 33 : 32;
+       flush_fp_to_thread(target);
 
-       if (copy_to_user(data, task->thread.fpr, count * sizeof(double)))
-               return -EFAULT;
-       return 0;
+       BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
+                    offsetof(struct thread_struct, fpr[32]));
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  &target->thread.fpr, 0, -1);
 }
 
-static int set_fpregs(void __user *data, struct task_struct *task,
-                     int has_fpscr)
+static int fpr_set(struct task_struct *target, const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
 {
-       unsigned int count = has_fpscr ? 33 : 32;
+       flush_fp_to_thread(target);
 
-       if (copy_from_user(task->thread.fpr, data, count * sizeof(double)))
-               return -EFAULT;
-       return 0;
+       BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
+                    offsetof(struct thread_struct, fpr[32]));
+
+       return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                 &target->thread.fpr, 0, -1);
 }
 
 
@@ -138,56 +252,74 @@ static int set_fpregs(void __user *data, struct task_struct *task,
  * (combined (32- and 64-bit) gdb.
  */
 
-/*
- * Get contents of AltiVec register state in task TASK
- */
-static int get_vrregs(unsigned long __user *data, struct task_struct *task)
+static int vr_active(struct task_struct *target,
+                    const struct user_regset *regset)
 {
-       unsigned long regsize;
+       flush_altivec_to_thread(target);
+       return target->thread.used_vr ? regset->n : 0;
+}
 
-       /* copy AltiVec registers VR[0] .. VR[31] */
-       regsize = 32 * sizeof(vector128);
-       if (copy_to_user(data, task->thread.vr, regsize))
-               return -EFAULT;
-       data += (regsize / sizeof(unsigned long));
+static int vr_get(struct task_struct *target, const struct user_regset *regset,
+                 unsigned int pos, unsigned int count,
+                 void *kbuf, void __user *ubuf)
+{
+       int ret;
 
-       /* copy VSCR */
-       regsize = 1 * sizeof(vector128);
-       if (copy_to_user(data, &task->thread.vscr, regsize))
-               return -EFAULT;
-       data += (regsize / sizeof(unsigned long));
+       flush_altivec_to_thread(target);
 
-       /* copy VRSAVE */
-       if (put_user(task->thread.vrsave, (u32 __user *)data))
-               return -EFAULT;
+       BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
+                    offsetof(struct thread_struct, vr[32]));
 
-       return 0;
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 &target->thread.vr, 0,
+                                 33 * sizeof(vector128));
+       if (!ret) {
+               /*
+                * Copy out only the low-order word of vrsave.
+                */
+               union {
+                       elf_vrreg_t reg;
+                       u32 word;
+               } vrsave;
+               memset(&vrsave, 0, sizeof(vrsave));
+               vrsave.word = target->thread.vrsave;
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
+                                         33 * sizeof(vector128), -1);
+       }
+
+       return ret;
 }
 
-/*
- * Write contents of AltiVec register state into task TASK.
- */
-static int set_vrregs(struct task_struct *task, unsigned long __user *data)
+static int vr_set(struct task_struct *target, const struct user_regset *regset,
+                 unsigned int pos, unsigned int count,
+                 const void *kbuf, const void __user *ubuf)
 {
-       unsigned long regsize;
+       int ret;
 
-       /* copy AltiVec registers VR[0] .. VR[31] */
-       regsize = 32 * sizeof(vector128);
-       if (copy_from_user(task->thread.vr, data, regsize))
-               return -EFAULT;
-       data += (regsize / sizeof(unsigned long));
+       flush_altivec_to_thread(target);
 
-       /* copy VSCR */
-       regsize = 1 * sizeof(vector128);
-       if (copy_from_user(&task->thread.vscr, data, regsize))
-               return -EFAULT;
-       data += (regsize / sizeof(unsigned long));
+       BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
+                    offsetof(struct thread_struct, vr[32]));
 
-       /* copy VRSAVE */
-       if (get_user(task->thread.vrsave, (u32 __user *)data))
-               return -EFAULT;
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &target->thread.vr, 0, 33 * sizeof(vector128));
+       if (!ret && count > 0) {
+               /*
+                * We use only the first word of vrsave.
+                */
+               union {
+                       elf_vrreg_t reg;
+                       u32 word;
+               } vrsave;
+               memset(&vrsave, 0, sizeof(vrsave));
+               vrsave.word = target->thread.vrsave;
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
+                                        33 * sizeof(vector128), -1);
+               if (!ret)
+                       target->thread.vrsave = vrsave.word;
+       }
 
-       return 0;
+       return ret;
 }
 #endif /* CONFIG_ALTIVEC */
 
@@ -203,57 +335,273 @@ static int set_vrregs(struct task_struct *task, unsigned long __user *data)
  * }
  */
 
-/*
- * Get contents of SPE register state in task TASK.
- */
-static int get_evrregs(unsigned long *data, struct task_struct *task)
+static int evr_active(struct task_struct *target,
+                     const struct user_regset *regset)
 {
-       int i;
+       flush_spe_to_thread(target);
+       return target->thread.used_spe ? regset->n : 0;
+}
 
-       if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
-               return -EFAULT;
+static int evr_get(struct task_struct *target, const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+       int ret;
 
-       /* copy SPEFSCR */
-       if (__put_user(task->thread.spefscr, &data[34]))
-               return -EFAULT;
+       flush_spe_to_thread(target);
 
-       /* copy SPE registers EVR[0] .. EVR[31] */
-       for (i = 0; i < 32; i++, data++)
-               if (__put_user(task->thread.evr[i], data))
-                       return -EFAULT;
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 &target->thread.evr,
+                                 0, sizeof(target->thread.evr));
 
-       /* copy ACC */
-       if (__put_user64(task->thread.acc, (unsigned long long *)data))
-               return -EFAULT;
+       BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
+                    offsetof(struct thread_struct, spefscr));
 
-       return 0;
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         &target->thread.acc,
+                                         sizeof(target->thread.evr), -1);
+
+       return ret;
+}
+
+static int evr_set(struct task_struct *target, const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       flush_spe_to_thread(target);
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &target->thread.evr,
+                                0, sizeof(target->thread.evr));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
+                    offsetof(struct thread_struct, spefscr));
+
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                        &target->thread.acc,
+                                        sizeof(target->thread.evr), -1);
+
+       return ret;
 }
+#endif /* CONFIG_SPE */
+
 
 /*
- * Write contents of SPE register state into task TASK.
+ * These are our native regset flavors.
  */
-static int set_evrregs(struct task_struct *task, unsigned long *data)
+enum powerpc_regset {
+       REGSET_GPR,
+       REGSET_FPR,
+#ifdef CONFIG_ALTIVEC
+       REGSET_VMX,
+#endif
+#ifdef CONFIG_SPE
+       REGSET_SPE,
+#endif
+};
+
+static const struct user_regset native_regsets[] = {
+       [REGSET_GPR] = {
+               .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
+               .size = sizeof(long), .align = sizeof(long),
+               .get = gpr_get, .set = gpr_set
+       },
+       [REGSET_FPR] = {
+               .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
+               .size = sizeof(double), .align = sizeof(double),
+               .get = fpr_get, .set = fpr_set
+       },
+#ifdef CONFIG_ALTIVEC
+       [REGSET_VMX] = {
+               .core_note_type = NT_PPC_VMX, .n = 34,
+               .size = sizeof(vector128), .align = sizeof(vector128),
+               .active = vr_active, .get = vr_get, .set = vr_set
+       },
+#endif
+#ifdef CONFIG_SPE
+       [REGSET_SPE] = {
+               .n = 35,
+               .size = sizeof(u32), .align = sizeof(u32),
+               .active = evr_active, .get = evr_get, .set = evr_set
+       },
+#endif
+};
+
+static const struct user_regset_view user_ppc_native_view = {
+       .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI,
+       .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
+};
+
+#ifdef CONFIG_PPC64
+#include <linux/compat.h>
+
+static int gpr32_get(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    void *kbuf, void __user *ubuf)
 {
-       int i;
+       const unsigned long *regs = &target->thread.regs->gpr[0];
+       compat_ulong_t *k = kbuf;
+       compat_ulong_t __user *u = ubuf;
+       compat_ulong_t reg;
+
+       if (target->thread.regs == NULL)
+               return -EIO;
+
+       CHECK_FULL_REGS(target->thread.regs);
 
-       if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
-               return -EFAULT;
+       pos /= sizeof(reg);
+       count /= sizeof(reg);
 
-       /* copy SPEFSCR */
-       if (__get_user(task->thread.spefscr, &data[34]))
-               return -EFAULT;
+       if (kbuf)
+               for (; count > 0 && pos < PT_MSR; --count)
+                       *k++ = regs[pos++];
+       else
+               for (; count > 0 && pos < PT_MSR; --count)
+                       if (__put_user((compat_ulong_t) regs[pos++], u++))
+                               return -EFAULT;
 
-       /* copy SPE registers EVR[0] .. EVR[31] */
-       for (i = 0; i < 32; i++, data++)
-               if (__get_user(task->thread.evr[i], data))
+       if (count > 0 && pos == PT_MSR) {
+               reg = get_user_msr(target);
+               if (kbuf)
+                       *k++ = reg;
+               else if (__put_user(reg, u++))
                        return -EFAULT;
-       /* copy ACC */
-       if (__get_user64(task->thread.acc, (unsigned long long*)data))
-               return -EFAULT;
+               ++pos;
+               --count;
+       }
 
-       return 0;
+       if (kbuf)
+               for (; count > 0 && pos < PT_REGS_COUNT; --count)
+                       *k++ = regs[pos++];
+       else
+               for (; count > 0 && pos < PT_REGS_COUNT; --count)
+                       if (__put_user((compat_ulong_t) regs[pos++], u++))
+                               return -EFAULT;
+
+       kbuf = k;
+       ubuf = u;
+       pos *= sizeof(reg);
+       count *= sizeof(reg);
+       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                       PT_REGS_COUNT * sizeof(reg), -1);
+}
+
+static int gpr32_set(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    const void *kbuf, const void __user *ubuf)
+{
+       unsigned long *regs = &target->thread.regs->gpr[0];
+       const compat_ulong_t *k = kbuf;
+       const compat_ulong_t __user *u = ubuf;
+       compat_ulong_t reg;
+
+       if (target->thread.regs == NULL)
+               return -EIO;
+
+       CHECK_FULL_REGS(target->thread.regs);
+
+       pos /= sizeof(reg);
+       count /= sizeof(reg);
+
+       if (kbuf)
+               for (; count > 0 && pos < PT_MSR; --count)
+                       regs[pos++] = *k++;
+       else
+               for (; count > 0 && pos < PT_MSR; --count) {
+                       if (__get_user(reg, u++))
+                               return -EFAULT;
+                       regs[pos++] = reg;
+               }
+
+
+       if (count > 0 && pos == PT_MSR) {
+               if (kbuf)
+                       reg = *k++;
+               else if (__get_user(reg, u++))
+                       return -EFAULT;
+               set_user_msr(target, reg);
+               ++pos;
+               --count;
+       }
+
+       if (kbuf)
+               for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
+                       regs[pos++] = *k++;
+       else
+               for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
+                       if (__get_user(reg, u++))
+                               return -EFAULT;
+                       regs[pos++] = reg;
+               }
+
+       if (count > 0 && pos == PT_TRAP) {
+               if (kbuf)
+                       reg = *k++;
+               else if (__get_user(reg, u++))
+                       return -EFAULT;
+               set_user_trap(target, reg);
+               ++pos;
+               --count;
+       }
+
+       kbuf = k;
+       ubuf = u;
+       pos *= sizeof(reg);
+       count *= sizeof(reg);
+       return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                        (PT_TRAP + 1) * sizeof(reg), -1);
+}
+
+/*
+ * These are the regset flavors matching the CONFIG_PPC32 native set.
+ */
+static const struct user_regset compat_regsets[] = {
+       [REGSET_GPR] = {
+               .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
+               .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
+               .get = gpr32_get, .set = gpr32_set
+       },
+       [REGSET_FPR] = {
+               .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
+               .size = sizeof(double), .align = sizeof(double),
+               .get = fpr_get, .set = fpr_set
+       },
+#ifdef CONFIG_ALTIVEC
+       [REGSET_VMX] = {
+               .core_note_type = NT_PPC_VMX, .n = 34,
+               .size = sizeof(vector128), .align = sizeof(vector128),
+               .active = vr_active, .get = vr_get, .set = vr_set
+       },
+#endif
+#ifdef CONFIG_SPE
+       [REGSET_SPE] = {
+               .core_note_type = NT_PPC_SPE, .n = 35,
+               .size = sizeof(u32), .align = sizeof(u32),
+               .active = evr_active, .get = evr_get, .set = evr_set
+       },
+#endif
+};
+
+static const struct user_regset_view user_ppc_compat_view = {
+       .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI,
+       .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets)
+};
+#endif /* CONFIG_PPC64 */
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+#ifdef CONFIG_PPC64
+       if (test_tsk_thread_flag(task, TIF_32BIT))
+               return &user_ppc_compat_view;
+#endif
+       return &user_ppc_native_view;
 }
-#endif /* CONFIG_SPE */
 
 
 void user_enable_single_step(struct task_struct *task)
@@ -323,55 +671,29 @@ void ptrace_disable(struct task_struct *child)
 static long arch_ptrace_old(struct task_struct *child, long request, long addr,
                            long data)
 {
-       int ret = -EPERM;
-
-       switch(request) {
-       case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
-               int i;
-               unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
-               unsigned long __user *tmp = (unsigned long __user *)addr;
-
-               CHECK_FULL_REGS(child->thread.regs);
-               for (i = 0; i < 32; i++) {
-                       ret = put_user(*reg, tmp);
-                       if (ret)
-                               break;
-                       reg++;
-                       tmp++;
-               }
-               break;
-       }
-
-       case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
-               int i;
-               unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
-               unsigned long __user *tmp = (unsigned long __user *)addr;
-
-               CHECK_FULL_REGS(child->thread.regs);
-               for (i = 0; i < 32; i++) {
-                       ret = get_user(*reg, tmp);
-                       if (ret)
-                               break;
-                       reg++;
-                       tmp++;
-               }
-               break;
-       }
-
-       case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
-               flush_fp_to_thread(child);
-               ret = get_fpregs((void __user *)addr, child, 0);
-               break;
-       }
-
-       case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
-               flush_fp_to_thread(child);
-               ret = set_fpregs((void __user *)addr, child, 0);
-               break;
+       switch (request) {
+       case PPC_PTRACE_GETREGS:        /* Get GPRs 0 - 31. */
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_GPR, 0, 32 * sizeof(long),
+                                          (void __user *) data);
+
+       case PPC_PTRACE_SETREGS:        /* Set GPRs 0 - 31. */
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                            REGSET_GPR, 0, 32 * sizeof(long),
+                                            (const void __user *) data);
+
+       case PPC_PTRACE_GETFPREGS:      /* Get FPRs 0 - 31. */
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_FPR, 0, 32 * sizeof(double),
+                                          (void __user *) data);
+
+       case PPC_PTRACE_SETFPREGS:      /* Set FPRs 0 - 31. */
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                            REGSET_FPR, 0, 32 * sizeof(double),
+                                            (const void __user *) data);
        }
 
-       }
-       return ret;
+       return -EPERM;
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -379,12 +701,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        int ret = -EPERM;
 
        switch (request) {
-       /* when I and D space are separate, these will need to be fixed. */
-       case PTRACE_PEEKTEXT: /* read word at location addr. */
-       case PTRACE_PEEKDATA:
-               ret = generic_ptrace_peekdata(child, addr, data);
-               break;
-
        /* read the word at location addr in the USER area. */
        case PTRACE_PEEKUSR: {
                unsigned long index, tmp;
@@ -412,12 +728,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                break;
        }
 
-       /* If I and D space are separate, this will have to be fixed. */
-       case PTRACE_POKETEXT: /* write the word at location addr. */
-       case PTRACE_POKEDATA:
-               ret = generic_ptrace_pokedata(child, addr, data);
-               break;
-
        /* write the word at location addr in the USER area */
        case PTRACE_POKEUSR: {
                unsigned long index;
@@ -462,85 +772,60 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 #ifdef CONFIG_PPC64
        case PTRACE_GETREGS64:
 #endif
-       case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
-               int ui;
-               if (!access_ok(VERIFY_WRITE, (void __user *)data,
-                              sizeof(struct pt_regs))) {
-                       ret = -EIO;
-                       break;
-               }
-               CHECK_FULL_REGS(child->thread.regs);
-               ret = 0;
-               for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
-                       ret |= __put_user(ptrace_get_reg(child, ui),
-                                         (unsigned long __user *) data);
-                       data += sizeof(long);
-               }
-               break;
-       }
+       case PTRACE_GETREGS:    /* Get all pt_regs from the child. */
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_GPR,
+                                          0, sizeof(struct pt_regs),
+                                          (void __user *) data);
 
 #ifdef CONFIG_PPC64
        case PTRACE_SETREGS64:
 #endif
-       case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-               unsigned long tmp;
-               int ui;
-               if (!access_ok(VERIFY_READ, (void __user *)data,
-                              sizeof(struct pt_regs))) {
-                       ret = -EIO;
-                       break;
-               }
-               CHECK_FULL_REGS(child->thread.regs);
-               ret = 0;
-               for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
-                       ret = __get_user(tmp, (unsigned long __user *) data);
-                       if (ret)
-                               break;
-                       ptrace_put_reg(child, ui, tmp);
-                       data += sizeof(long);
-               }
-               break;
-       }
-
-       case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
-               flush_fp_to_thread(child);
-               ret = get_fpregs((void __user *)data, child, 1);
-               break;
-       }
-
-       case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
-               flush_fp_to_thread(child);
-               ret = set_fpregs((void __user *)data, child, 1);
-               break;
-       }
+       case PTRACE_SETREGS:    /* Set all gp regs in the child. */
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                            REGSET_GPR,
+                                            0, sizeof(struct pt_regs),
+                                            (const void __user *) data);
+
+       case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_FPR,
+                                          0, sizeof(elf_fpregset_t),
+                                          (void __user *) data);
+
+       case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                            REGSET_FPR,
+                                            0, sizeof(elf_fpregset_t),
+                                            (const void __user *) data);
 
 #ifdef CONFIG_ALTIVEC
        case PTRACE_GETVRREGS:
-               /* Get the child altivec register state. */
-               flush_altivec_to_thread(child);
-               ret = get_vrregs((unsigned long __user *)data, child);
-               break;
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_VMX,
+                                          0, (33 * sizeof(vector128) +
+                                              sizeof(u32)),
+                                          (void __user *) data);
 
        case PTRACE_SETVRREGS:
-               /* Set the child altivec register state. */
-               flush_altivec_to_thread(child);
-               ret = set_vrregs(child, (unsigned long __user *)data);
-               break;
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                            REGSET_VMX,
+                                            0, (33 * sizeof(vector128) +
+                                                sizeof(u32)),
+                                            (const void __user *) data);
 #endif
 #ifdef CONFIG_SPE
        case PTRACE_GETEVRREGS:
                /* Get the child spe register state. */
-               flush_spe_to_thread(child);
-               ret = get_evrregs((unsigned long __user *)data, child);
-               break;
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_SPE, 0, 35 * sizeof(u32),
+                                          (void __user *) data);
 
        case PTRACE_SETEVRREGS:
                /* Set the child spe register state. */
-               /* this is to clear the MSR_SPE bit to force a reload
-                * of register state from memory */
-               flush_spe_to_thread(child);
-               ret = set_evrregs(child, (unsigned long __user *)data);
-               break;
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                            REGSET_SPE, 0, 35 * sizeof(u32),
+                                            (const void __user *) data);
 #endif
 
        /* Old reverse args ptrace callss */
index fea6206ff90fd69aaf363075181a927049cb552d..4c1de6af4c092da35128e6ae553af27a3dcb9baf 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
+#include <linux/regset.h>
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/signal.h>
+#include <linux/compat.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
 static long compat_ptrace_old(struct task_struct *child, long request,
                              long addr, long data)
 {
-       int ret = -EPERM;
-
-       switch(request) {
-       case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
-               int i;
-               unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
-               unsigned int __user *tmp = (unsigned int __user *)addr;
-
-               CHECK_FULL_REGS(child->thread.regs);
-               for (i = 0; i < 32; i++) {
-                       ret = put_user(*reg, tmp);
-                       if (ret)
-                               break;
-                       reg++;
-                       tmp++;
-               }
-               break;
-       }
-
-       case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
-               int i;
-               unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
-               unsigned int __user *tmp = (unsigned int __user *)addr;
-
-               CHECK_FULL_REGS(child->thread.regs);
-               for (i = 0; i < 32; i++) {
-                       ret = get_user(*reg, tmp);
-                       if (ret)
-                               break;
-                       reg++;
-                       tmp++;
-               }
-               break;
+       switch (request) {
+       case PPC_PTRACE_GETREGS:        /* Get GPRs 0 - 31. */
+               return copy_regset_to_user(child,
+                                          task_user_regset_view(current), 0,
+                                          0, 32 * sizeof(compat_long_t),
+                                          compat_ptr(data));
+
+       case PPC_PTRACE_SETREGS:        /* Set GPRs 0 - 31. */
+               return copy_regset_from_user(child,
+                                            task_user_regset_view(current), 0,
+                                            0, 32 * sizeof(compat_long_t),
+                                            compat_ptr(data));
        }
 
-       }
-       return ret;
+       return -EPERM;
 }
 
-long compat_sys_ptrace(int request, int pid, unsigned long addr,
-                      unsigned long data)
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+                       compat_ulong_t caddr, compat_ulong_t cdata)
 {
-       struct task_struct *child;
+       unsigned long addr = caddr;
+       unsigned long data = cdata;
        int ret;
 
-       lock_kernel();
-       if (request == PTRACE_TRACEME) {
-               ret = ptrace_traceme();
-               goto out;
-       }
-
-       child = ptrace_get_task_struct(pid);
-       if (IS_ERR(child)) {
-               ret = PTR_ERR(child);
-               goto out;
-       }
-
-       if (request == PTRACE_ATTACH) {
-               ret = ptrace_attach(child);
-               goto out_tsk;
-       }
-
-       ret = ptrace_check_attach(child, request == PTRACE_KILL);
-       if (ret < 0)
-               goto out_tsk;
-
        switch (request) {
-       /* when I and D space are separate, these will need to be fixed. */
-       case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-       case PTRACE_PEEKDATA: {
-               unsigned int tmp;
-               int copied;
-
-               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-               ret = -EIO;
-               if (copied != sizeof(tmp))
-                       break;
-               ret = put_user(tmp, (u32 __user *)data);
-               break;
-       }
-
        /*
         * Read 4 bytes of the other process' storage
         *  data is a pointer specifying where the user wants the
@@ -225,19 +171,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                break;
        }
 
-       /* If I and D space are separate, this will have to be fixed. */
-       case PTRACE_POKETEXT: /* write the word at location addr. */
-       case PTRACE_POKEDATA: {
-               unsigned int tmp;
-               tmp = data;
-               ret = 0;
-               if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1)
-                               == sizeof(tmp))
-                       break;
-               ret = -EIO;
-               break;
-       }
-
        /*
         * Write 4 bytes into the other process' storage
         *  data is the 4 bytes that the user wants written
@@ -337,46 +270,17 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                break;
        }
 
-       case PTRACE_GETEVENTMSG:
-               ret = put_user(child->ptrace_message, (unsigned int __user *) data);
-               break;
+       case PTRACE_GETREGS:    /* Get all pt_regs from the child. */
+               return copy_regset_to_user(
+                       child, task_user_regset_view(current), 0,
+                       0, PT_REGS_COUNT * sizeof(compat_long_t),
+                       compat_ptr(data));
 
-       case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
-               int ui;
-               if (!access_ok(VERIFY_WRITE, (void __user *)data,
-                              PT_REGS_COUNT * sizeof(int))) {
-                       ret = -EIO;
-                       break;
-               }
-               CHECK_FULL_REGS(child->thread.regs);
-               ret = 0;
-               for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
-                       ret |= __put_user(ptrace_get_reg(child, ui),
-                                         (unsigned int __user *) data);
-                       data += sizeof(int);
-               }
-               break;
-       }
-
-       case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-               unsigned long tmp;
-               int ui;
-               if (!access_ok(VERIFY_READ, (void __user *)data,
-                              PT_REGS_COUNT * sizeof(int))) {
-                       ret = -EIO;
-                       break;
-               }
-               CHECK_FULL_REGS(child->thread.regs);
-               ret = 0;
-               for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
-                       ret = __get_user(tmp, (unsigned int __user *) data);
-                       if (ret)
-                               break;
-                       ptrace_put_reg(child, ui, tmp);
-                       data += sizeof(int);
-               }
-               break;
-       }
+       case PTRACE_SETREGS:    /* Set all gp regs in the child. */
+               return copy_regset_from_user(
+                       child, task_user_regset_view(current), 0,
+                       0, PT_REGS_COUNT * sizeof(compat_long_t),
+                       compat_ptr(data));
 
        case PTRACE_GETFPREGS:
        case PTRACE_SETFPREGS:
@@ -402,12 +306,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                break;
 
        default:
-               ret = ptrace_request(child, request, addr, data);
+               ret = compat_ptrace_request(child, request, addr, data);
                break;
        }
-out_tsk:
-       put_task_struct(child);
-out:
-       unlock_kernel();
+
        return ret;
 }
index 848a20475db8c29deafdfe12380b746d0d4613ad..4b5b7ff4f78bb0e4564718fd7836f3a1542dae9f 100644 (file)
@@ -54,7 +54,7 @@
 #endif
 #include <asm/kexec.h>
 
-#ifdef CONFIG_DEBUGGER
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 int (*__debugger)(struct pt_regs *regs);
 int (*__debugger_ipi)(struct pt_regs *regs);
 int (*__debugger_bpt)(struct pt_regs *regs);
index f0bad7070fb54087d241f6a81bf9ea875f71156b..f98867252ee269afac74dba19e04a5c0a629a07f 100644 (file)
@@ -176,7 +176,7 @@ static void __devinit vio_dev_release(struct device *dev)
  * Returns a pointer to the created vio_dev or NULL if node has
  * NULL device_type or compatible fields.
  */
-struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
+struct vio_dev *vio_register_device_node(struct device_node *of_node)
 {
        struct vio_dev *viodev;
        const unsigned int *unit_address;
index e8122447f019ef81b5346ab911f82bd3c4439cd6..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? */
@@ -483,7 +485,12 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
                 */
                _tlbie(address, 0 /* 8xx doesn't care about PID */);
 #endif
-               if (!PageReserved(page)
+               /* The _PAGE_USER test should really be _PAGE_EXEC, but
+                * older glibc versions execute some code from no-exec
+                * pages, which for now we are supporting.  If exec-only
+                * pages are ever implemented, this will have to change.
+                */
+               if (!PageReserved(page) && (pte_val(pte) & _PAGE_USER)
                    && !test_bit(PG_arch_1, &page->flags)) {
                        if (vma->vm_mm == current->active_mm) {
                                __flush_dcache_icache((void *) address);
index c12adc3ddffd892b3238025873afc7764eb20831..a300d254aac6518dc473ecf405bebf6943b6bfeb 100644 (file)
@@ -24,6 +24,8 @@
 
 static int numa_enabled = 1;
 
+static char *cmdline __initdata;
+
 static int numa_debug;
 #define dbg(args...) if (numa_debug) { printk(KERN_INFO args); }
 
@@ -39,6 +41,53 @@ static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
 static int min_common_depth;
 static int n_mem_addr_cells, n_mem_size_cells;
 
+static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
+                                               unsigned int *nid)
+{
+       unsigned long long mem;
+       char *p = cmdline;
+       static unsigned int fake_nid;
+       static unsigned long long curr_boundary;
+
+       /*
+        * Modify node id, iff we started creating NUMA nodes
+        * We want to continue from where we left of the last time
+        */
+       if (fake_nid)
+               *nid = fake_nid;
+       /*
+        * In case there are no more arguments to parse, the
+        * node_id should be the same as the last fake node id
+        * (we've handled this above).
+        */
+       if (!p)
+               return 0;
+
+       mem = memparse(p, &p);
+       if (!mem)
+               return 0;
+
+       if (mem < curr_boundary)
+               return 0;
+
+       curr_boundary = mem;
+
+       if ((end_pfn << PAGE_SHIFT) > mem) {
+               /*
+                * Skip commas and spaces
+                */
+               while (*p == ',' || *p == ' ' || *p == '\t')
+                       p++;
+
+               cmdline = p;
+               fake_nid++;
+               *nid = fake_nid;
+               dbg("created new fake_node with id %d\n", fake_nid);
+               return 1;
+       }
+       return 0;
+}
+
 static void __cpuinit map_cpu_to_node(int cpu, int node)
 {
        numa_cpu_lookup_table[cpu] = node;
@@ -344,6 +393,9 @@ static void __init parse_drconf_memory(struct device_node *memory)
                        if (nid == 0xffff || nid >= MAX_NUMNODES)
                                nid = default_nid;
                }
+
+               fake_numa_create_new_node(((start + lmb_size) >> PAGE_SHIFT),
+                                               &nid);
                node_set_online(nid);
 
                size = numa_enforce_memory_limit(start, lmb_size);
@@ -429,6 +481,8 @@ new_range:
                nid = of_node_to_nid_single(memory);
                if (nid < 0)
                        nid = default_nid;
+
+               fake_numa_create_new_node(((start + size) >> PAGE_SHIFT), &nid);
                node_set_online(nid);
 
                if (!(size = numa_enforce_memory_limit(start, size))) {
@@ -461,7 +515,7 @@ static void __init setup_nonnuma(void)
        unsigned long top_of_ram = lmb_end_of_DRAM();
        unsigned long total_ram = lmb_phys_mem_size();
        unsigned long start_pfn, end_pfn;
-       unsigned int i;
+       unsigned int i, nid = 0;
 
        printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
               top_of_ram, total_ram);
@@ -471,9 +525,11 @@ static void __init setup_nonnuma(void)
        for (i = 0; i < lmb.memory.cnt; ++i) {
                start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
                end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
-               add_active_range(0, start_pfn, end_pfn);
+
+               fake_numa_create_new_node(end_pfn, &nid);
+               add_active_range(nid, start_pfn, end_pfn);
+               node_set_online(nid);
        }
-       node_set_online(0);
 }
 
 void __init dump_numa_cpu_topology(void)
@@ -675,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);
                        }
                }
 
@@ -702,6 +758,10 @@ static int __init early_numa(char *p)
        if (strstr(p, "debug"))
                numa_debug = 1;
 
+       p = strstr(p, "fake=");
+       if (p)
+               cmdline = p + strlen("fake=");
+
        return 0;
 }
 early_param("numa", early_numa);
index c5f64c3bd668a21615dcc714c96a144a272bbcfe..2ef6b0dddd8c3fec59df6ea6db780facd6171d36 100644 (file)
@@ -15,5 +15,5 @@ oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
                cell/spu_profiler.o cell/vma_map.o \
                cell/spu_task_sync.o
 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
-oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
+oprofile-$(CONFIG_FSL_EMB_PERFMON) += op_model_fsl_emb.o
 oprofile-$(CONFIG_6xx) += op_model_7450.o
index a28cce1d6c24628b82a5e01eb40677557b0bf23f..4908dc98f9caa2368129a7c7f16ed477ec1bebec 100644 (file)
@@ -202,9 +202,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
                        model = &op_model_7450;
                        break;
 #endif
-#ifdef CONFIG_FSL_BOOKE
-               case PPC_OPROFILE_BOOKE:
-                       model = &op_model_fsl_booke;
+#if defined(CONFIG_FSL_EMB_PERFMON)
+               case PPC_OPROFILE_FSL_EMB:
+                       model = &op_model_fsl_emb;
                        break;
 #endif
                default:
similarity index 90%
rename from arch/powerpc/oprofile/op_model_fsl_booke.c
rename to arch/powerpc/oprofile/op_model_fsl_emb.c
index 183a28bb1812e7b57f503acc1abbb0d18ec64d8d..91596f6ba1f497e4c277150922c105c662bc7a3c 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * arch/powerpc/oprofile/op_model_fsl_booke.c
- *
- * Freescale Book-E oprofile support, based on ppc64 oprofile support
+ * Freescale Embedded oprofile support, based on ppc64 oprofile support
  * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
  *
  * Copyright (c) 2004 Freescale Semiconductor, Inc
@@ -22,7 +20,7 @@
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
-#include <asm/reg_booke.h>
+#include <asm/reg_fsl_emb.h>
 #include <asm/page.h>
 #include <asm/pmc.h>
 #include <asm/oprofile_impl.h>
@@ -244,7 +242,7 @@ static void dump_pmcs(void)
                        mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
 }
 
-static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
+static int fsl_emb_cpu_setup(struct op_counter_config *ctr)
 {
        int i;
 
@@ -262,7 +260,7 @@ static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
        return 0;
 }
 
-static int fsl_booke_reg_setup(struct op_counter_config *ctr,
+static int fsl_emb_reg_setup(struct op_counter_config *ctr,
                             struct op_system_config *sys,
                             int num_ctrs)
 {
@@ -281,7 +279,7 @@ static int fsl_booke_reg_setup(struct op_counter_config *ctr,
        return 0;
 }
 
-static int fsl_booke_start(struct op_counter_config *ctr)
+static int fsl_emb_start(struct op_counter_config *ctr)
 {
        int i;
 
@@ -315,7 +313,7 @@ static int fsl_booke_start(struct op_counter_config *ctr)
        return 0;
 }
 
-static void fsl_booke_stop(void)
+static void fsl_emb_stop(void)
 {
        /* freeze counters */
        pmc_stop_ctrs();
@@ -329,7 +327,7 @@ static void fsl_booke_stop(void)
 }
 
 
-static void fsl_booke_handle_interrupt(struct pt_regs *regs,
+static void fsl_emb_handle_interrupt(struct pt_regs *regs,
                                    struct op_counter_config *ctr)
 {
        unsigned long pc;
@@ -362,10 +360,10 @@ static void fsl_booke_handle_interrupt(struct pt_regs *regs,
        pmc_start_ctrs(1);
 }
 
-struct op_powerpc_model op_model_fsl_booke = {
-       .reg_setup              = fsl_booke_reg_setup,
-       .cpu_setup              = fsl_booke_cpu_setup,
-       .start                  = fsl_booke_start,
-       .stop                   = fsl_booke_stop,
-       .handle_interrupt       = fsl_booke_handle_interrupt,
+struct op_powerpc_model op_model_fsl_emb = {
+       .reg_setup              = fsl_emb_reg_setup,
+       .cpu_setup              = fsl_emb_cpu_setup,
+       .start                  = fsl_emb_start,
+       .stop                   = fsl_emb_stop,
+       .handle_interrupt       = fsl_emb_handle_interrupt,
 };
index 74f31177e47a44e3aaf6dd0282c41af42a52bb41..a9260e21451e5b884cc3affe056945eaf2fd049f 100644 (file)
@@ -72,6 +72,7 @@ config WALNUT
        default y
        select 405GP
        select PCI
+       select OF_RTC
        help
          This option enables support for the IBM PPC405GP evaluation board.
 
index 88b66444dfb24df543a76692f426d9ea8156b765..0422590040db5dbf12468db78624dab41f69adb5 100644 (file)
@@ -37,7 +37,7 @@ static int __init virtex_probe(void)
 {
        unsigned long root = of_get_flat_dt_root();
 
-       if (!of_flat_dt_is_compatible(root, "xilinx,virtex"))
+       if (!of_flat_dt_is_compatible(root, "xlnx,virtex"))
                return 0;
 
        return 1;
index 5d9edd917f925382b4f3b5d920842dfb14cf297e..b8b257efeb773aaa0c3ee8b642088670c82db7e0 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/init.h>
 #include <linux/of_platform.h>
+#include <linux/rtc.h>
 
 #include <asm/machdep.h>
 #include <asm/prom.h>
index 8f01563dbd2aa3d8aacb16a7629a961f6103ae97..da5b7b7599dbc3d0a19b649630d8e2d6fcc739ae 100644 (file)
@@ -137,7 +137,7 @@ static int __init pika_dtm_start(void)
        }
        of_node_put(np);
 
-       fpga = ioremap(res.start + 0x20, 4);
+       fpga = ioremap(res.start, 0x24);
        if (fpga == NULL)
                return -ENOENT;
 
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
new file mode 100644 (file)
index 0000000..c6fa49e
--- /dev/null
@@ -0,0 +1,20 @@
+config PPC_MPC512x
+       bool
+       select FSL_SOC
+       select IPIC
+       default n
+
+config PPC_MPC5121
+       bool
+       select PPC_MPC512x
+       default n
+
+config MPC5121_ADS
+       bool "Freescale MPC5121E ADS"
+       depends on PPC_MULTIPLATFORM && PPC32
+       select DEFAULT_UIMAGE
+       select WANT_DEVICE_TREE
+       select PPC_MPC5121
+       help
+         This option enables support for the MPC5121E ADS board.
+       default n
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
new file mode 100644 (file)
index 0000000..232c89f
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Makefile for the Freescale PowerPC 512x linux kernel.
+#
+obj-$(CONFIG_MPC5121_ADS)      += mpc5121_ads.o
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
new file mode 100644 (file)
index 0000000..50bd3a3
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007
+ *
+ * Description:
+ * MPC5121 ADS board setup
+ *
+ * This 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/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+
+/**
+ *     mpc512x_find_ips_freq - Find the IPS bus frequency for a device
+ *     @node:  device node
+ *
+ *     Returns IPS bus frequency, or 0 if the bus frequency cannot be found.
+ */
+unsigned long
+mpc512x_find_ips_freq(struct device_node *node)
+{
+       struct device_node *np;
+       const unsigned int *p_ips_freq = NULL;
+
+       of_node_get(node);
+       while (node) {
+               p_ips_freq = of_get_property(node, "bus-frequency", NULL);
+               if (p_ips_freq)
+                       break;
+
+               np = of_get_parent(node);
+               of_node_put(node);
+               node = np;
+       }
+       if (node)
+               of_node_put(node);
+
+       return p_ips_freq ? *p_ips_freq : 0;
+}
+EXPORT_SYMBOL(mpc512x_find_ips_freq);
+
+static struct of_device_id __initdata of_bus_ids[] = {
+       { .name = "soc", },
+       { .name = "localbus", },
+       {},
+};
+
+static void __init mpc5121_ads_declare_of_platform_devices(void)
+{
+       /* Find every child of the SOC node and add it to of_platform */
+       if (of_platform_bus_probe(NULL, of_bus_ids, NULL))
+               printk(KERN_ERR __FILE__ ": "
+                       "Error while probing of_platform bus\n");
+}
+
+static void __init mpc5121_ads_init_IRQ(void)
+{
+       struct device_node *np;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,ipic");
+       if (!np)
+               return;
+
+       ipic_init(np, 0);
+       of_node_put(np);
+
+       /*
+        * Initialize the default interrupt mapping priorities,
+        * in case the boot rom changed something on us.
+        */
+       ipic_set_default_priority();
+}
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc5121_ads_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,mpc5121ads");
+}
+
+define_machine(mpc5121_ads) {
+       .name                   = "MPC5121 ADS",
+       .probe                  = mpc5121_ads_probe,
+       .init                   = mpc5121_ads_declare_of_platform_devices,
+       .init_IRQ               = mpc5121_ads_init_IRQ,
+       .get_irq                = ipic_get_irq,
+       .calibrate_decr         = generic_calibrate_decr,
+};
index 3fce6b375dbc5f1d709701281987af8a2f483647..7d3018751988b4994d9024dca1dc38ce88b934f0 100644 (file)
@@ -134,13 +134,12 @@ static void __init mpc8272_ads_setup_arch(void)
        }
 
        bcsr = of_iomap(np, 0);
+       of_node_put(np);
        if (!bcsr) {
                printk(KERN_ERR "Cannot map BCSR registers\n");
                return;
        }
 
-       of_node_put(np);
-
        clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
        setbits32(&bcsr[1], BCSR1_FETH_RST);
 
index 68196e349994afd50d5de9f07e826facc5494c90..e1dceeec49944aba3e07ecb967abe37e07c822bf 100644 (file)
@@ -130,13 +130,12 @@ static void __init pq2fads_setup_arch(void)
        }
 
        bcsr = of_iomap(np, 0);
+       of_node_put(np);
        if (!bcsr) {
                printk(KERN_ERR "Cannot map BCSR registers\n");
                return;
        }
 
-       of_node_put(np);
-
        /* Enable the serial and ethernet ports */
 
        clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
index 9f0fd88b2b1f16e1a6126436fd9635ab2e5f19ae..e7f706b624feeb574a3e7f3a91d34c5b39192c0e 100644 (file)
@@ -101,7 +101,7 @@ static void __init mpc832x_rdb_setup_arch(void)
 #ifdef CONFIG_QUICC_ENGINE
        qe_reset();
 
-       if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+       if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
                par_io_init(np);
                of_node_put(np);
 
index 88bb748aff0d7568a06aa7ffac4455afbd942c05..68065e62fc3d35faa42e69974ead970f13e154ed 100644 (file)
@@ -14,6 +14,8 @@
 #define MPC83XX_SCCR_USB_DRCM_11   0x00300000
 #define MPC83XX_SCCR_USB_DRCM_01   0x00100000
 #define MPC83XX_SCCR_USB_DRCM_10   0x00200000
+#define MPC8315_SCCR_USB_MASK      0x00c00000
+#define MPC8315_SCCR_USB_DRCM_11   0x00c00000
 #define MPC837X_SCCR_USB_DRCM_11   0x00c00000
 
 /* system i/o configuration register low */
index 681230a30acd7029cc10a0041b3c74567a781348..471fdd8f41084b629bc962534bc58dce2fadee93 100644 (file)
@@ -104,6 +104,7 @@ int mpc831x_usb_cfg(void)
        u32 temp;
        void __iomem *immap, *usb_regs;
        struct device_node *np = NULL;
+       struct device_node *immr_node = NULL;
        const void *prop;
        struct resource res;
        int ret = 0;
@@ -124,10 +125,15 @@ int mpc831x_usb_cfg(void)
        }
 
        /* Configure clock */
-       temp = in_be32(immap + MPC83XX_SCCR_OFFS);
-       temp &= ~MPC83XX_SCCR_USB_MASK;
-       temp |= MPC83XX_SCCR_USB_DRCM_11;  /* 1:3 */
-       out_be32(immap + MPC83XX_SCCR_OFFS, temp);
+       immr_node = of_get_parent(np);
+       if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
+               clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
+                               MPC8315_SCCR_USB_MASK,
+                               MPC8315_SCCR_USB_DRCM_11);
+       else
+               clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
+                               MPC83XX_SCCR_USB_MASK,
+                               MPC83XX_SCCR_USB_DRCM_11);
 
        /* Configure pin mux for ULPI.  There is no pin mux for UTMI */
        if (prop && !strcmp(prop, "ulpi")) {
@@ -144,6 +150,9 @@ int mpc831x_usb_cfg(void)
 
        iounmap(immap);
 
+       if (immr_node)
+               of_node_put(immr_node);
+
        /* Map USB SOC space */
        ret = of_address_to_resource(np, 0, &res);
        if (ret) {
index c6bc0783c3b0819074d24b14f4f71b71beb25a9e..82363e98f50e4bc05240df0c147e65a3168b2c65 100644 (file)
 
 #include <asm/time.h>
 #include <asm/machdep.h>
-#include <asm/commproc.h>
+#include <asm/cpm1.h>
 #include <asm/fs_pd.h>
 #include <asm/udbg.h>
 #include <asm/prom.h>
 
-#include <sysdev/commproc.h>
+#include "mpc8xx.h"
 
 struct cpm_pin {
        int port, pin, flags;
@@ -108,7 +108,7 @@ define_machine(adder875) {
        .name = "Adder MPC875",
        .probe = adder875_probe,
        .setup_arch = adder875_setup,
-       .init_IRQ = m8xx_pic_init,
+       .init_IRQ = mpc8xx_pics_init,
        .get_irq = mpc8xx_get_irq,
        .restart = mpc8xx_restart,
        .calibrate_decr = generic_calibrate_decr,
index a8dffa005775f167b02949b04f58d9d38a296f0e..7d9ac6040d631f7f4bc19edb37056999249e3c40 100644 (file)
@@ -15,7 +15,6 @@
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/udbg.h>
-#include <asm/commproc.h>
 #include <asm/cpm1.h>
 
 #include "mpc8xx.h"
index fdce10c4f07440e2e23dddd28018c710712e6399..fcedbec07f94fe7478f50f19833afe3b9c87a20e 100644 (file)
@@ -24,6 +24,7 @@ config PPC_83xx
        select MPC83xx
        select IPIC
        select WANT_DEVICE_TREE
+       select FSL_EMB_PERFMON
 
 config PPC_86xx
        bool "Freescale 86xx"
@@ -41,6 +42,7 @@ config CLASSIC32
 source "arch/powerpc/platforms/pseries/Kconfig"
 source "arch/powerpc/platforms/iseries/Kconfig"
 source "arch/powerpc/platforms/chrp/Kconfig"
+source "arch/powerpc/platforms/512x/Kconfig"
 source "arch/powerpc/platforms/52xx/Kconfig"
 source "arch/powerpc/platforms/powermac/Kconfig"
 source "arch/powerpc/platforms/prep/Kconfig"
index 7fc41104d53eb8aee659bc9b909ad2da2680e0dd..69941ba709753fe0972f125aa2121c857161aa3d 100644 (file)
@@ -14,7 +14,7 @@ choice
          There are five families of 32 bit PowerPC chips supported.
          The most common ones are the desktop and server CPUs (601, 603,
          604, 740, 750, 74xx) CPUs from Freescale and IBM, with their
-         embedded 52xx/82xx/83xx/86xx counterparts.
+         embedded 512x/52xx/82xx/83xx/86xx counterparts.
          The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500
          (85xx) each form a family of their own that is not compatible
          with the others.
@@ -22,7 +22,7 @@ choice
          If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
 
 config 6xx
-       bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx"
+       bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
        select PPC_FPU
 
 config PPC_85xx
@@ -94,6 +94,7 @@ config 8xx
        bool
 
 config E500
+       select FSL_EMB_PERFMON
        bool
 
 config PPC_FPU
@@ -115,6 +116,9 @@ config FSL_BOOKE
        depends on E200 || E500
        default y
 
+config FSL_EMB_PERFMON
+       bool
+
 config PTE_64BIT
        bool
        depends on 44x || E500
@@ -221,7 +225,7 @@ config NR_CPUS
 
 config NOT_COHERENT_CACHE
        bool
-       depends on 4xx || 8xx || E200
+       depends on 4xx || 8xx || E200 || PPC_MPC512x
        default y
 
 config CHECK_CACHE_COHERENCY
index 6d9079da5f5a917c9357faa19f22300dab43f178..a984894466d91c23dcafe92e97932e31c9d43bf3 100644 (file)
@@ -11,6 +11,7 @@ endif
 obj-$(CONFIG_PPC_CHRP)         += chrp/
 obj-$(CONFIG_40x)              += 40x/
 obj-$(CONFIG_44x)              += 44x/
+obj-$(CONFIG_PPC_MPC512x)      += 512x/
 obj-$(CONFIG_PPC_MPC52xx)      += 52xx/
 obj-$(CONFIG_PPC_8xx)          += 8xx/
 obj-$(CONFIG_PPC_82xx)         += 82xx/
index 3a963b4a9be0fcca0457e97a980f37bc6a63f4a9..2f169991896d9a2d8e33524df82675e2d5e2278b 100644 (file)
@@ -54,6 +54,13 @@ config SPU_FS_64K_LS
          uses 4K pages. This can improve performances of applications
          using multiple SPEs by lowering the TLB pressure on them.
 
+config SPU_TRACE
+       tristate "SPU event tracing support"
+       depends on SPU_FS && MARKERS
+       help
+         This option allows reading a trace of spu-related events through
+         the sputrace file in procfs.
+
 config SPU_BASE
        bool
        default n
index 095988f13bf4de8eca56f1c16457751dfb198a72..d95e71dee91f85f000a1662c200f2075b6bec95f 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
-#include <linux/reboot.h>
+#include <linux/of_platform.h>
 
 #include <asm/dcr.h>
 #include <asm/machdep.h>
 
 struct axon_msic {
        struct irq_host *irq_host;
-       __le32 *fifo;
+       __le32 *fifo_virt;
+       dma_addr_t fifo_phys;
        dcr_host_t dcr_host;
-       struct list_head list;
        u32 read_offset;
 };
 
-static LIST_HEAD(axon_msic_list);
-
 static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
 {
        pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
@@ -94,7 +92,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
 
        while (msic->read_offset != write_offset) {
                idx  = msic->read_offset / sizeof(__le32);
-               msi  = le32_to_cpu(msic->fifo[idx]);
+               msi  = le32_to_cpu(msic->fifo_virt[idx]);
                msi &= 0xFFFF;
 
                pr_debug("axon_msi: woff %x roff %x msi %x\n",
@@ -139,6 +137,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
 
        tmp = dn;
        dn = of_find_node_by_phandle(*ph);
+       of_node_put(tmp);
        if (!dn) {
                dev_dbg(&dev->dev,
                        "axon_msi: msi-translator doesn't point to a node\n");
@@ -156,7 +155,6 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
 
 out_error:
        of_node_put(dn);
-       of_node_put(tmp);
 
        return msic;
 }
@@ -292,30 +290,24 @@ static struct irq_host_ops msic_host_ops = {
        .map    = msic_host_map,
 };
 
-static int axon_msi_notify_reboot(struct notifier_block *nb,
-                                 unsigned long code, void *data)
+static int axon_msi_shutdown(struct of_device *device)
 {
-       struct axon_msic *msic;
+       struct axon_msic *msic = device->dev.platform_data;
        u32 tmp;
 
-       list_for_each_entry(msic, &axon_msic_list, list) {
-               pr_debug("axon_msi: disabling %s\n",
-                         msic->irq_host->of_node->full_name);
-               tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
-               tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
-               msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
-       }
+       pr_debug("axon_msi: disabling %s\n",
+                 msic->irq_host->of_node->full_name);
+       tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
+       tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
+       msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
 
        return 0;
 }
 
-static struct notifier_block axon_msi_reboot_notifier = {
-       .notifier_call = axon_msi_notify_reboot
-};
-
-static int axon_msi_setup_one(struct device_node *dn)
+static int axon_msi_probe(struct of_device *device,
+                         const struct of_device_id *device_id)
 {
-       struct page *page;
+       struct device_node *dn = device->node;
        struct axon_msic *msic;
        unsigned int virq;
        int dcr_base, dcr_len;
@@ -346,16 +338,14 @@ static int axon_msi_setup_one(struct device_node *dn)
                goto out_free_msic;
        }
 
-       page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
-                               get_order(MSIC_FIFO_SIZE_BYTES));
-       if (!page) {
+       msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES,
+                                            &msic->fifo_phys, GFP_KERNEL);
+       if (!msic->fifo_virt) {
                printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
                       dn->full_name);
                goto out_free_msic;
        }
 
-       msic->fifo = page_address(page);
-
        msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
                                        NR_IRQS, &msic_host_ops, 0);
        if (!msic->irq_host) {
@@ -378,14 +368,18 @@ static int axon_msi_setup_one(struct device_node *dn)
        pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
 
        /* Enable the MSIC hardware */
-       msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
+       msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
        msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
-                                 (u64)msic->fifo & 0xFFFFFFFF);
+                                 msic->fifo_phys & 0xFFFFFFFF);
        msic_dcr_write(msic, MSIC_CTRL_REG,
                        MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
                        MSIC_CTRL_FIFO_SIZE);
 
-       list_add(&msic->list, &axon_msic_list);
+       device->dev.platform_data = msic;
+
+       ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
+       ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
+       ppc_md.msi_check_device = axon_msi_check_device;
 
        printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
 
@@ -394,7 +388,8 @@ static int axon_msi_setup_one(struct device_node *dn)
 out_free_host:
        kfree(msic->irq_host);
 out_free_fifo:
-       __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
+       dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt,
+                         msic->fifo_phys);
 out_free_msic:
        kfree(msic);
 out:
@@ -402,28 +397,24 @@ out:
        return -1;
 }
 
-static int axon_msi_init(void)
-{
-       struct device_node *dn;
-       int found = 0;
-
-       pr_debug("axon_msi: initialising ...\n");
-
-       for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
-               if (axon_msi_setup_one(dn) == 0)
-                       found++;
-       }
-
-       if (found) {
-               ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
-               ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
-               ppc_md.msi_check_device = axon_msi_check_device;
-
-               register_reboot_notifier(&axon_msi_reboot_notifier);
+static const struct of_device_id axon_msi_device_id[] = {
+       {
+               .compatible     = "ibm,axon-msic"
+       },
+       {}
+};
 
-               pr_debug("axon_msi: registered callbacks!\n");
-       }
+static struct of_platform_driver axon_msi_driver = {
+       .match_table    = axon_msi_device_id,
+       .probe          = axon_msi_probe,
+       .shutdown       = axon_msi_shutdown,
+       .driver         = {
+               .name   = "axon-msi"
+       },
+};
 
-       return 0;
+static int __init axon_msi_init(void)
+{
+       return of_register_platform_driver(&axon_msi_driver);
 }
-arch_initcall(axon_msi_init);
+subsys_initcall(axon_msi_init);
index e6534b519c9abb71267299eb313c1b9535571634..a7f609b3b876d61b1f128bf3902f8262761d0927 100644 (file)
@@ -98,7 +98,7 @@ static int __init cell_publish_devices(void)
        }
        return 0;
 }
-machine_device_initcall(cell, cell_publish_devices);
+machine_subsys_initcall(cell, cell_publish_devices);
 
 static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
 {
index d3a349fb42e58c9b2164a45a6bbb46d804aae72a..99610a6361f28133e1eff58c32d4e91455afa92f 100644 (file)
@@ -4,6 +4,8 @@ spufs-y += inode.o file.o context.o syscalls.o coredump.o
 spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o
 spufs-y += switch.o fault.o lscsa_alloc.o
 
+obj-$(CONFIG_SPU_TRACE)        += sputrace.o
+
 # Rules to build switch.o with the help of SPU tool chain
 SPU_CROSS      := spu-
 SPU_CC         := $(SPU_CROSS)gcc
index 3fcd06418b01d165ba1d01f7d9930608d6d15c6d..1018acd1746b76f7ac99ef91b62092d4d45529d6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/poll.h>
 #include <linux/ptrace.h>
 #include <linux/seq_file.h>
+#include <linux/marker.h>
 
 #include <asm/io.h>
 #include <asm/semaphore.h>
@@ -358,6 +359,8 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
        struct spu_context *ctx = vma->vm_file->private_data;
        unsigned long area, offset = address - vma->vm_start;
 
+       spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx);
+
        offset += vma->vm_pgoff << PAGE_SHIFT;
        if (offset >= ps_size)
                return NOPFN_SIGBUS;
@@ -375,11 +378,14 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
 
        if (ctx->state == SPU_STATE_SAVED) {
                up_read(&current->mm->mmap_sem);
+               spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx);
                spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE);
+               spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu);
                down_read(&current->mm->mmap_sem);
        } else {
                area = ctx->spu->problem_phys + ps_offs;
                vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT);
+               spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu);
        }
 
        spu_release(ctx);
index c0e968a4c21116d5ffd4a8bfb8ed7182cc79f15d..90784c029f25096ae46963e6fc035c9eaad6c1d5 100644 (file)
@@ -322,7 +322,7 @@ static struct spu_context *
 spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
                                                struct file *filp)
 {
-       struct spu_context *tmp, *neighbor;
+       struct spu_context *tmp, *neighbor, *err;
        int count, node;
        int aff_supp;
 
@@ -354,11 +354,15 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
                if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
                    !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
                    !list_entry(neighbor->aff_list.next, struct spu_context,
-                   aff_list)->aff_head)
-                       return ERR_PTR(-EEXIST);
+                   aff_list)->aff_head) {
+                       err = ERR_PTR(-EEXIST);
+                       goto out_put_neighbor;
+               }
 
-               if (gang != neighbor->gang)
-                       return ERR_PTR(-EINVAL);
+               if (gang != neighbor->gang) {
+                       err = ERR_PTR(-EINVAL);
+                       goto out_put_neighbor;
+               }
 
                count = 1;
                list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
@@ -372,11 +376,17 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
                                break;
                }
 
-               if (node == MAX_NUMNODES)
-                       return ERR_PTR(-EEXIST);
+               if (node == MAX_NUMNODES) {
+                       err = ERR_PTR(-EEXIST);
+                       goto out_put_neighbor;
+               }
        }
 
        return neighbor;
+
+out_put_neighbor:
+       put_spu_context(neighbor);
+       return err;
 }
 
 static void
@@ -454,9 +464,12 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
        if (ret)
                goto out_aff_unlock;
 
-       if (affinity)
+       if (affinity) {
                spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
                                                                neighbor);
+               if (neighbor)
+                       put_spu_context(neighbor);
+       }
 
        /*
         * get references for dget and mntget, will be released
index c01a09da1e562b277ce8000396b7ae382c2758fc..b4814c740d8a7b065453e410a3057fd77a4d9b4f 100644 (file)
@@ -410,8 +410,11 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
         * since we have TIF_SINGLESTEP set, thus the kernel will do
         * it upon return from the syscall anyawy
         */
-       if ((status & SPU_STATUS_STOPPED_BY_STOP)
-           && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
+       if (unlikely(status & SPU_STATUS_SINGLE_STEP))
+               ret = -ERESTARTSYS;
+
+       else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP)
+           && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) {
                force_sig(SIGTRAP, current);
                ret = -ERESTARTSYS;
        }
index 00d914232af1450318f1c08256c3a0da91d47294..5915343e2599b313320b2ca18edb42cdecec60e2 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/marker.h>
 
 #include <asm/io.h>
 #include <asm/mmu_context.h>
@@ -216,8 +217,8 @@ void do_notify_spus_active(void)
  */
 static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
 {
-       pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
-                spu->number, spu->node);
+       spu_context_trace(spu_bind_context__enter, ctx, spu);
+
        spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
 
        if (ctx->flags & SPU_CREATE_NOSCHED)
@@ -399,8 +400,8 @@ static int has_affinity(struct spu_context *ctx)
  */
 static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
 {
-       pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
-                spu->pid, spu->number, spu->node);
+       spu_context_trace(spu_unbind_context__enter, ctx, spu);
+
        spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
 
        if (spu->ctx->flags & SPU_CREATE_NOSCHED)
@@ -528,6 +529,8 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
        struct spu *spu, *aff_ref_spu;
        int node, n;
 
+       spu_context_nospu_trace(spu_get_idle__enter, ctx);
+
        if (ctx->gang) {
                mutex_lock(&ctx->gang->aff_mutex);
                if (has_affinity(ctx)) {
@@ -546,8 +549,7 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
                        if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
                                ctx->gang->aff_ref_spu = NULL;
                        mutex_unlock(&ctx->gang->aff_mutex);
-
-                       return NULL;
+                       goto not_found;
                }
                mutex_unlock(&ctx->gang->aff_mutex);
        }
@@ -565,12 +567,14 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
                mutex_unlock(&cbe_spu_info[node].list_mutex);
        }
 
+ not_found:
+       spu_context_nospu_trace(spu_get_idle__not_found, ctx);
        return NULL;
 
  found:
        spu->alloc_state = SPU_USED;
        mutex_unlock(&cbe_spu_info[node].list_mutex);
-       pr_debug("Got SPU %d %d\n", spu->number, spu->node);
+       spu_context_trace(spu_get_idle__found, ctx, spu);
        spu_init_channels(spu);
        return spu;
 }
@@ -587,6 +591,8 @@ static struct spu *find_victim(struct spu_context *ctx)
        struct spu *spu;
        int node, n;
 
+       spu_context_nospu_trace(spu_find_vitim__enter, ctx);
+
        /*
         * Look for a possible preemption candidate on the local node first.
         * If there is no candidate look at the other nodes.  This isn't
@@ -640,6 +646,8 @@ static struct spu *find_victim(struct spu_context *ctx)
                                goto restart;
                        }
 
+                       spu_context_trace(__spu_deactivate__unload, ctx, spu);
+
                        mutex_lock(&cbe_spu_info[node].list_mutex);
                        cbe_spu_info[node].nr_active--;
                        spu_unbind_context(spu, victim);
@@ -822,6 +830,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
  */
 void spu_deactivate(struct spu_context *ctx)
 {
+       spu_context_nospu_trace(spu_deactivate__enter, ctx);
        __spu_deactivate(ctx, 1, MAX_PRIO);
 }
 
@@ -835,6 +844,7 @@ void spu_deactivate(struct spu_context *ctx)
  */
 void spu_yield(struct spu_context *ctx)
 {
+       spu_context_nospu_trace(spu_yield__enter, ctx);
        if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
                mutex_lock(&ctx->state_mutex);
                __spu_deactivate(ctx, 0, MAX_PRIO);
@@ -864,11 +874,15 @@ static noinline void spusched_tick(struct spu_context *ctx)
                goto out;
 
        spu = ctx->spu;
+
+       spu_context_trace(spusched_tick__preempt, ctx, spu);
+
        new = grab_runnable_context(ctx->prio + 1, spu->node);
        if (new) {
                spu_unschedule(spu, ctx);
                spu_add_to_rq(ctx);
        } else {
+               spu_context_nospu_trace(spusched_tick__newslice, ctx);
                ctx->time_slice++;
        }
 out:
index 0e114038ea6fc136b5ec74e675987d848553629f..795a1b52538b7f093a9d2d8251a75dac2d300ba5 100644 (file)
@@ -325,4 +325,9 @@ extern void spu_free_lscsa(struct spu_state *csa);
 extern void spuctx_switch_state(struct spu_context *ctx,
                enum spu_utilization_state new_state);
 
+#define spu_context_trace(name, ctx, spu) \
+       trace_mark(name, "%p %p", ctx, spu);
+#define spu_context_nospu_trace(name, ctx) \
+       trace_mark(name, "%p", ctx);
+
 #endif
diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c
new file mode 100644 (file)
index 0000000..2b1953f
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2007 IBM Deutschland Entwicklung GmbH
+ *     Released under GPL v2.
+ *
+ * Partially based on net/ipv4/tcp_probe.c.
+ *
+ * Simple tracing facility for spu contexts.
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <linux/proc_fs.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+#include "spufs.h"
+
+struct spu_probe {
+       const char *name;
+       const char *format;
+       marker_probe_func *probe_func;
+};
+
+struct sputrace {
+       ktime_t tstamp;
+       int owner_tid; /* owner */
+       int curr_tid;
+       const char *name;
+       int number;
+};
+
+static int bufsize __read_mostly = 16384;
+MODULE_PARM_DESC(bufsize, "Log buffer size (number of records)");
+module_param(bufsize, int, 0);
+
+
+static DEFINE_SPINLOCK(sputrace_lock);
+static DECLARE_WAIT_QUEUE_HEAD(sputrace_wait);
+static ktime_t sputrace_start;
+static unsigned long sputrace_head, sputrace_tail;
+static struct sputrace *sputrace_log;
+
+static int sputrace_used(void)
+{
+       return (sputrace_head - sputrace_tail) % bufsize;
+}
+
+static inline int sputrace_avail(void)
+{
+       return bufsize - sputrace_used();
+}
+
+static int sputrace_sprint(char *tbuf, int n)
+{
+       const struct sputrace *t = sputrace_log + sputrace_tail % bufsize;
+       struct timespec tv =
+               ktime_to_timespec(ktime_sub(t->tstamp, sputrace_start));
+
+       return snprintf(tbuf, n,
+               "[%lu.%09lu] %d: %s (thread = %d, spu = %d)\n",
+               (unsigned long) tv.tv_sec,
+               (unsigned long) tv.tv_nsec,
+               t->owner_tid,
+               t->name,
+               t->curr_tid,
+               t->number);
+}
+
+static ssize_t sputrace_read(struct file *file, char __user *buf,
+               size_t len, loff_t *ppos)
+{
+       int error = 0, cnt = 0;
+
+       if (!buf || len < 0)
+               return -EINVAL;
+
+       while (cnt < len) {
+               char tbuf[128];
+               int width;
+
+               error = wait_event_interruptible(sputrace_wait,
+                                                sputrace_used() > 0);
+               if (error)
+                       break;
+
+               spin_lock(&sputrace_lock);
+               if (sputrace_head == sputrace_tail) {
+                       spin_unlock(&sputrace_lock);
+                       continue;
+               }
+
+               width = sputrace_sprint(tbuf, sizeof(tbuf));
+               if (width < len)
+                       sputrace_tail = (sputrace_tail + 1) % bufsize;
+               spin_unlock(&sputrace_lock);
+
+               if (width >= len)
+                       break;
+
+               error = copy_to_user(buf + cnt, tbuf, width);
+               if (error)
+                       break;
+               cnt += width;
+       }
+
+       return cnt == 0 ? error : cnt;
+}
+
+static int sputrace_open(struct inode *inode, struct file *file)
+{
+       spin_lock(&sputrace_lock);
+       sputrace_head = sputrace_tail = 0;
+       sputrace_start = ktime_get();
+       spin_unlock(&sputrace_lock);
+
+       return 0;
+}
+
+static const struct file_operations sputrace_fops = {
+       .owner  = THIS_MODULE,
+       .open   = sputrace_open,
+       .read   = sputrace_read,
+};
+
+static void sputrace_log_item(const char *name, struct spu_context *ctx,
+               struct spu *spu)
+{
+       spin_lock(&sputrace_lock);
+       if (sputrace_avail() > 1) {
+               struct sputrace *t = sputrace_log + sputrace_head;
+
+               t->tstamp = ktime_get();
+               t->owner_tid = ctx->tid;
+               t->name = name;
+               t->curr_tid = current->pid;
+               t->number = spu ? spu->number : -1;
+
+               sputrace_head = (sputrace_head + 1) % bufsize;
+       } else {
+               printk(KERN_WARNING
+                      "sputrace: lost samples due to full buffer.\n");
+       }
+       spin_unlock(&sputrace_lock);
+
+       wake_up(&sputrace_wait);
+}
+
+static void spu_context_event(const struct marker *mdata,
+               void *private, const char *format, ...)
+{
+       struct spu_probe *p = mdata->private;
+       va_list ap;
+       struct spu_context *ctx;
+       struct spu *spu;
+
+       va_start(ap, format);
+       ctx = va_arg(ap, struct spu_context *);
+       spu = va_arg(ap, struct spu *);
+
+       sputrace_log_item(p->name, ctx, spu);
+       va_end(ap);
+}
+
+static void spu_context_nospu_event(const struct marker *mdata,
+               void *private, const char *format, ...)
+{
+       struct spu_probe *p = mdata->private;
+       va_list ap;
+       struct spu_context *ctx;
+
+       va_start(ap, format);
+       ctx = va_arg(ap, struct spu_context *);
+
+       sputrace_log_item(p->name, ctx, NULL);
+       va_end(ap);
+}
+
+struct spu_probe spu_probes[] = {
+       { "spu_bind_context__enter", "%p %p", spu_context_event },
+       { "spu_unbind_context__enter", "%p %p", spu_context_event },
+       { "spu_get_idle__enter", "%p", spu_context_nospu_event },
+       { "spu_get_idle__found", "%p %p", spu_context_event },
+       { "spu_get_idle__not_found", "%p", spu_context_nospu_event },
+       { "spu_find_victim__enter", "%p", spu_context_nospu_event },
+       { "spusched_tick__preempt", "%p %p", spu_context_event },
+       { "spusched_tick__newslice", "%p", spu_context_nospu_event },
+       { "spu_yield__enter", "%p", spu_context_nospu_event },
+       { "spu_deactivate__enter", "%p", spu_context_nospu_event },
+       { "__spu_deactivate__unload", "%p %p", spu_context_event },
+       { "spufs_ps_nopfn__enter", "%p", spu_context_nospu_event },
+       { "spufs_ps_nopfn__sleep", "%p", spu_context_nospu_event },
+       { "spufs_ps_nopfn__wake", "%p %p", spu_context_event },
+       { "spufs_ps_nopfn__insert", "%p %p", spu_context_event },
+       { "spu_acquire_saved__enter", "%p", spu_context_nospu_event },
+       { "destroy_spu_context__enter", "%p", spu_context_nospu_event },
+};
+
+static int __init sputrace_init(void)
+{
+       struct proc_dir_entry *entry;
+       int i, error = -ENOMEM;
+
+       sputrace_log = kcalloc(sizeof(struct sputrace),
+                               bufsize, GFP_KERNEL);
+       if (!sputrace_log)
+               goto out;
+
+       entry = create_proc_entry("sputrace", S_IRUSR, NULL);
+       if (!entry)
+               goto out_free_log;
+       entry->proc_fops = &sputrace_fops;
+
+       for (i = 0; i < ARRAY_SIZE(spu_probes); i++) {
+               struct spu_probe *p = &spu_probes[i];
+
+               error = marker_probe_register(p->name, p->format,
+                                             p->probe_func, p);
+               if (error)
+                       printk(KERN_INFO "Unable to register probe %s\n",
+                                       p->name);
+
+               error = marker_arm(p->name);
+               if (error)
+                       printk(KERN_INFO "Unable to arm probe %s\n", p->name);
+       }
+
+       return 0;
+
+out_free_log:
+       kfree(sputrace_log);
+out:
+       return -ENOMEM;
+}
+
+static void __exit sputrace_exit(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(spu_probes); i++)
+               marker_probe_unregister(spu_probes[i].name);
+
+       remove_proc_entry("sputrace", NULL);
+       kfree(sputrace_log);
+}
+
+module_init(sputrace_init);
+module_exit(sputrace_exit);
+
+MODULE_LICENSE("GPL");
index e12e9d2987162f7e306d285439192cc66c1a29bc..8864e488498012700e8a0608429cbd8a67195a61 100644 (file)
@@ -132,33 +132,18 @@ static void __init storcenter_init_IRQ(void)
 
        paddr = (phys_addr_t)of_translate_address(dnp, prop);
        mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET,
-                       4, 32, " EPIC     ");
+                       16, 32, " OpenPIC  ");
 
        of_node_put(dnp);
 
        BUG_ON(mpic == NULL);
 
-       /* PCI IRQs */
        /*
-        * 2.6.12 patch:
-        *         openpic_set_sources(0, 5, OpenPIC_Addr + 0x10200);
-        *         openpic_set_sources(5, 2, OpenPIC_Addr + 0x11120);
-        *         first_irq, num_irqs, __iomem first_ISR
-        *         o_ss: i, src: 0, fdf50200
-        *         o_ss: i, src: 1, fdf50220
-        *         o_ss: i, src: 2, fdf50240
-        *         o_ss: i, src: 3, fdf50260
-        *         o_ss: i, src: 4, fdf50280
-        *         o_ss: i, src: 5, fdf51120
-        *         o_ss: i, src: 6, fdf51140
+        * 16 Serial Interrupts followed by 16 Internal Interrupts.
+        * I2C is the second internal, so it is at 17, 0x11020.
         */
        mpic_assign_isu(mpic, 0, paddr + 0x10200);
-       mpic_assign_isu(mpic, 1, paddr + 0x10220);
-       mpic_assign_isu(mpic, 2, paddr + 0x10240);
-       mpic_assign_isu(mpic, 3, paddr + 0x10260);
-       mpic_assign_isu(mpic, 4, paddr + 0x10280);
-       mpic_assign_isu(mpic, 5, paddr + 0x11120);
-       mpic_assign_isu(mpic, 6, paddr + 0x11140);
+       mpic_assign_isu(mpic, 1, paddr + 0x11000);
 
        mpic_init(mpic);
 }
@@ -178,7 +163,7 @@ static int __init storcenter_probe(void)
 {
        unsigned long root = of_get_flat_dt_root();
 
-       return of_flat_dt_is_compatible(root, "storcenter");
+       return of_flat_dt_is_compatible(root, "iomega,storcenter");
 }
 
 define_machine(storcenter){
index c4ad54e0f288cde7934c1cbbdda987ea249e8e7b..1f032483c026e613b4ab84649ab2f3562fb7c031 100644 (file)
@@ -58,7 +58,7 @@ static void pseries_mach_cpu_die(void)
 {
        local_irq_disable();
        idle_task_exit();
-       xics_teardown_cpu(0);
+       xics_teardown_cpu();
        unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow()));
        rtas_stop_self();
        /* Should never get here... */
index 412a5e7aff2d33829f8d0f1483fba69d6d635003..e9dd5fe081c94bd66fad46ac416c0504699a0ca6 100644 (file)
@@ -54,7 +54,7 @@ void __init setup_kexec_cpu_down_mpic(void)
 static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary)
 {
        pseries_kexec_cpu_down(crash_shutdown, secondary);
-       xics_teardown_cpu(secondary);
+       xics_kexec_teardown_cpu(secondary);
 }
 
 void __init setup_kexec_cpu_down_xics(void)
index c02f8742c54de5792650c2e641003637921cad03..2800fced8c7c2952425620f3e6d32373608b4757 100644 (file)
@@ -167,6 +167,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
 
        if ((child = of_get_next_child(np, NULL))) {
                of_node_put(child);
+               of_node_put(parent);
                return -EBUSY;
        }
 
index 8f8dd9c3ca6b9dc499d7a2983d63770a9709a719..ca52b587166d950856f36bb4102aba8cb0f466e1 100644 (file)
@@ -160,6 +160,46 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
 
 /* High level handlers and init code */
 
+static void xics_update_irq_servers(void)
+{
+       int i, j;
+       struct device_node *np;
+       u32 ilen;
+       const u32 *ireg, *isize;
+       u32 hcpuid;
+
+       /* Find the server numbers for the boot cpu. */
+       np = of_get_cpu_node(boot_cpuid, NULL);
+       BUG_ON(!np);
+
+       ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+       if (!ireg) {
+               of_node_put(np);
+               return;
+       }
+
+       i = ilen / sizeof(int);
+       hcpuid = get_hard_smp_processor_id(boot_cpuid);
+
+       /* Global interrupt distribution server is specified in the last
+        * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
+        * entry fom this property for current boot cpu id and use it as
+        * default distribution server
+        */
+       for (j = 0; j < i; j += 2) {
+               if (ireg[j] == hcpuid) {
+                       default_server = hcpuid;
+                       default_distrib_server = ireg[j+1];
+
+                       isize = of_get_property(np,
+                                       "ibm,interrupt-server#-size", NULL);
+                       if (isize)
+                               interrupt_server_size = *isize;
+               }
+       }
+
+       of_node_put(np);
+}
 
 #ifdef CONFIG_SMP
 static int get_irq_server(unsigned int virq, unsigned int strict_check)
@@ -169,6 +209,9 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
        cpumask_t cpumask = irq_desc[virq].affinity;
        cpumask_t tmp = CPU_MASK_NONE;
 
+       if (! cpu_isset(default_server, cpu_online_map))
+               xics_update_irq_servers();
+
        if (!distribute_irqs)
                return default_server;
 
@@ -658,39 +701,11 @@ static void __init xics_setup_8259_cascade(void)
        set_irq_chained_handler(cascade, pseries_8259_cascade);
 }
 
-static struct device_node *cpuid_to_of_node(int cpu)
-{
-       struct device_node *np;
-       u32 hcpuid = get_hard_smp_processor_id(cpu);
-
-       for_each_node_by_type(np, "cpu") {
-               int i, len;
-               const u32 *intserv;
-
-               intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
-                                       &len);
-
-               if (!intserv)
-                       intserv = of_get_property(np, "reg", &len);
-
-               i = len / sizeof(u32);
-
-               while (i--)
-                       if (intserv[i] == hcpuid)
-                               return np;
-       }
-
-       return NULL;
-}
-
 void __init xics_init_IRQ(void)
 {
-       int i, j;
        struct device_node *np;
-       u32 ilen, indx = 0;
-       const u32 *ireg, *isize;
+       u32 indx = 0;
        int found = 0;
-       u32 hcpuid;
 
        ppc64_boot_msg(0x20, "XICS Init");
 
@@ -709,34 +724,7 @@ void __init xics_init_IRQ(void)
                return;
 
        xics_init_host();
-
-       /* Find the server numbers for the boot cpu. */
-       np = cpuid_to_of_node(boot_cpuid);
-       BUG_ON(!np);
-       ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
-       if (!ireg)
-               goto skip_gserver_check;
-       i = ilen / sizeof(int);
-       hcpuid = get_hard_smp_processor_id(boot_cpuid);
-
-       /* Global interrupt distribution server is specified in the last
-        * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
-        * entry fom this property for current boot cpu id and use it as
-        * default distribution server
-        */
-       for (j = 0; j < i; j += 2) {
-               if (ireg[j] == hcpuid) {
-                       default_server = hcpuid;
-                       default_distrib_server = ireg[j+1];
-
-                       isize = of_get_property(np,
-                                       "ibm,interrupt-server#-size", NULL);
-                       if (isize)
-                               interrupt_server_size = *isize;
-               }
-       }
-skip_gserver_check:
-       of_node_put(np);
+       xics_update_irq_servers();
 
        if (firmware_has_feature(FW_FEATURE_LPAR))
                ppc_md.get_irq = xics_get_irq_lpar;
@@ -775,11 +763,9 @@ void xics_request_IPIs(void)
 }
 #endif /* CONFIG_SMP */
 
-void xics_teardown_cpu(int secondary)
+void xics_teardown_cpu()
 {
        int cpu = smp_processor_id();
-       unsigned int ipi;
-       struct irq_desc *desc;
 
        xics_set_cpu_priority(0);
 
@@ -790,9 +776,17 @@ void xics_teardown_cpu(int secondary)
                lpar_qirr_info(cpu, 0xff);
        else
                direct_qirr_info(cpu, 0xff);
+}
+
+void xics_kexec_teardown_cpu(int secondary)
+{
+       unsigned int ipi;
+       struct irq_desc *desc;
+
+       xics_teardown_cpu();
 
        /*
-        * we need to EOI the IPI if we got here from kexec down IPI
+        * we need to EOI the IPI
         *
         * probably need to check all the other interrupts too
         * should we be flagging idle loop instead?
@@ -880,8 +874,8 @@ void xics_migrate_irqs_away(void)
                       virq, cpu);
 
                /* Reset affinity to all cpus */
+               irq_desc[virq].affinity = CPU_MASK_ALL;
                desc->chip->set_affinity(virq, CPU_MASK_ALL);
-               irq_desc[irq].affinity = CPU_MASK_ALL;
 unlock:
                spin_unlock_irqrestore(&desc->lock, flags);
        }
index 9ffd809d29e218dea80039b60fbe245d9b515497..c26bcff47b6dbbb9912cf3fc895da24bfd288444 100644 (file)
@@ -16,7 +16,8 @@
 
 extern void xics_init_IRQ(void);
 extern void xics_setup_cpu(void);
-extern void xics_teardown_cpu(int secondary);
+extern void xics_teardown_cpu(void);
+extern void xics_kexec_teardown_cpu(int secondary);
 extern void xics_cause_IPI(int cpu);
 extern  void xics_request_IPIs(void);
 extern void xics_migrate_irqs_away(void);
index 427027c7ea0f61fbeeb7192f2c1125cb64246d22..437e48d3ae3340d5817c10f20d2a6dfc8276daeb 100644 (file)
@@ -137,5 +137,6 @@ void dcr_unmap(dcr_host_t host, unsigned int dcr_c)
        h.token = NULL;
 }
 EXPORT_SYMBOL_GPL(dcr_unmap);
-
-#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */
+#else  /* defined(CONFIG_PPC_DCR_NATIVE) */
+DEFINE_SPINLOCK(dcr_ind_lock);
+#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */
index e48b20e934ca233e744be83b36744a15cbd7d6ad..2c5388ce902abfaa3fd9f400c231a3dd64735cc5 100644 (file)
@@ -1342,7 +1342,7 @@ static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
                if (ret)
                        goto unreg;
 
-               ret = platform_device_register(pdev);
+               ret = platform_device_add(pdev);
                if (ret)
                        goto unreg;
 
index 0e74a4bd9827df1e4558810f3f77e177b3ec607c..5d2d5522ef416846a0ba9bf8073c05652227d4c7 100644 (file)
@@ -174,15 +174,19 @@ int mpc8xx_pic_init(void)
                goto out;
 
        siu_reg = ioremap(res.start, res.end - res.start + 1);
-       if (siu_reg == NULL)
-               return -EINVAL;
+       if (siu_reg == NULL) {
+               ret = -EINVAL;
+               goto out;
+       }
 
-       mpc8xx_pic_host = irq_alloc_host(of_node_get(np), IRQ_HOST_MAP_LINEAR,
+       mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
                                         64, &mpc8xx_pic_host_ops, 64);
        if (mpc8xx_pic_host == NULL) {
                printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
                ret = -ENOMEM;
+               goto out;
        }
+       return 0;
 
 out:
        of_node_put(np);
index 5ef844da9355c15bcde600ab0121b4e45619f49e..6efbd5e5bb1b6f1b8119ed8ccf7e8ed35591a015 100644 (file)
@@ -66,7 +66,7 @@ phys_addr_t get_qe_base(void)
 {
        struct device_node *qe;
        unsigned int size;
-       const void *prop;
+       const u32 *prop;
 
        if (qebase != -1)
                return qebase;
@@ -79,7 +79,8 @@ phys_addr_t get_qe_base(void)
        }
 
        prop = of_get_property(qe, "reg", &size);
-       qebase = of_translate_address(qe, prop);
+       if (prop && size >= sizeof(*prop))
+               qebase = of_translate_address(qe, prop);
        of_node_put(qe);
 
        return qebase;
@@ -172,10 +173,9 @@ unsigned int get_brg_clk(void)
        }
 
        prop = of_get_property(qe, "brg-frequency", &size);
-       if (!prop || size != sizeof(*prop))
-               return brg_clk;
+       if (prop && size == sizeof(*prop))
+               brg_clk = *prop;
 
-       brg_clk = *prop;
        of_node_put(qe);
 
        return brg_clk;
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 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 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 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 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 e6728bd61cc106fdd71f0ce7a4a025db020a1348..c95482b6b6dd2f064701000db87519ec9bb621a7 100644 (file)
@@ -105,6 +105,9 @@ config GENERIC_TIME_VSYSCALL
        bool
        default X86_64
 
+config ARCH_HAS_CPU_RELAX
+       def_bool y
+
 config HAVE_SETUP_PER_CPU_AREA
        def_bool X86_64
 
@@ -631,7 +634,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 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 d2a58431a074b3f6282b58489635076878bdf2d3..680b7300a48966dc0162adc05577541d8cc47854 100644 (file)
@@ -78,7 +78,6 @@ int acpi_ht __initdata = 1;   /* enable HT */
 int acpi_lapic;
 int acpi_ioapic;
 int acpi_strict;
-EXPORT_SYMBOL(acpi_strict);
 
 u8 acpi_sci_flags __initdata;
 int acpi_sci_override_gsi __initdata;
@@ -106,7 +105,7 @@ enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;
 #ifdef CONFIG_X86_64
 
 /* rely on all ACPI tables being in the direct mapping */
-char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
+char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
 {
        if (!phys_addr || !size)
                return NULL;
@@ -131,7 +130,7 @@ char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
  * from the fixed base.  That's why we start at FIX_IO_APIC_BASE_END and
  * count idx down while incrementing the phys address.
  */
-char *__acpi_map_table(unsigned long phys, unsigned long size)
+char *__init __acpi_map_table(unsigned long phys, unsigned long size)
 {
        unsigned long base, offset, mapped_size;
        int idx;
@@ -490,8 +489,6 @@ int acpi_register_gsi(u32 gsi, int triggering, int polarity)
        return irq;
 }
 
-EXPORT_SYMBOL(acpi_register_gsi);
-
 /*
  *  ACPI based hotplug support for CPU
  */
@@ -587,25 +584,6 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
 
 EXPORT_SYMBOL(acpi_unregister_ioapic);
 
-static unsigned long __init
-acpi_scan_rsdp(unsigned long start, unsigned long length)
-{
-       unsigned long offset = 0;
-       unsigned long sig_len = sizeof("RSD PTR ") - 1;
-
-       /*
-        * Scan all 16-byte boundaries of the physical memory region for the
-        * RSDP signature.
-        */
-       for (offset = 0; offset < length; offset += 16) {
-               if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len))
-                       continue;
-               return (start + offset);
-       }
-
-       return 0;
-}
-
 static int __init acpi_parse_sbf(struct acpi_table_header *table)
 {
        struct acpi_table_boot *sb;
@@ -748,27 +726,6 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
        return 0;
 }
 
-unsigned long __init acpi_find_rsdp(void)
-{
-       unsigned long rsdp_phys = 0;
-
-       if (efi_enabled) {
-               if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
-                       return efi.acpi20;
-               else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
-                       return efi.acpi;
-       }
-       /*
-        * Scan memory looking for the RSDP signature. First search EBDA (low
-        * memory) paragraphs and then search upper memory (E0000-FFFFF).
-        */
-       rsdp_phys = acpi_scan_rsdp(0, 0x400);
-       if (!rsdp_phys)
-               rsdp_phys = acpi_scan_rsdp(0xE0000, 0x20000);
-
-       return rsdp_phys;
-}
-
 #ifdef CONFIG_X86_LOCAL_APIC
 /*
  * Parse LAPIC entries in MADT
index a25db514c719ef939bbb9e8069339a50e39c4dbc..324eb0cab19ceb7c8353f402d78884f139c6741d 100644 (file)
@@ -46,6 +46,12 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
        buf[1] = 1;
        buf[2] = ACPI_PDC_C_CAPABILITY_SMP;
 
+       /*
+        * The default of PDC_SMP_T_SWCOORD bit is set for intel x86 cpu so
+        * that OSPM is capable of native ACPI throttling software
+        * coordination using BIOS supplied _TSD info.
+        */
+       buf[2] |= ACPI_PDC_SMP_T_SWCOORD;
        if (cpu_has(c, X86_FEATURE_EST))
                buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP;
 
index 151eda0a23fc40be379c71b409b6cf846d0d3e2f..cb7a5715596dfa448e56eef69c92125afc9f0f77 100644 (file)
@@ -29,7 +29,7 @@ config X86_ACPI_CPUFREQ
 config ELAN_CPUFREQ
        tristate "AMD Elan SC400 and SC410"
        select CPU_FREQ_TABLE
-       depends on X86_32 && X86_ELAN
+       depends on X86_ELAN
        ---help---
          This adds the CPUFreq driver for AMD Elan SC400 and SC410
          processors.
@@ -45,7 +45,7 @@ config ELAN_CPUFREQ
 config SC520_CPUFREQ
        tristate "AMD Elan SC520"
        select CPU_FREQ_TABLE
-       depends on X86_32 && X86_ELAN
+       depends on X86_ELAN
        ---help---
          This adds the CPUFreq driver for AMD Elan SC520 processor.
 
index 326a4c81f68493cd8802ce13093689858577ad63..39f8cb18296c68fc74fa999a195f0d1fa20a9787 100644 (file)
@@ -23,6 +23,7 @@
 #define EPS_BRAND_C7   1
 #define EPS_BRAND_EDEN 2
 #define EPS_BRAND_C3   3
+#define EPS_BRAND_C7D  4
 
 struct eps_cpu_data {
        u32 fsb;
@@ -54,6 +55,7 @@ static int eps_set_state(struct eps_cpu_data *centaur,
 {
        struct cpufreq_freqs freqs;
        u32 lo, hi;
+       u8 current_multiplier, current_voltage;
        int err = 0;
        int i;
 
@@ -93,6 +95,15 @@ postchange:
        rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
        freqs.new = centaur->fsb * ((lo >> 8) & 0xff);
 
+       /* Print voltage and multiplier */
+       rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
+       current_voltage = lo & 0xff;
+       printk(KERN_INFO "eps: Current voltage = %dmV\n",
+               current_voltage * 16 + 700);
+       current_multiplier = (lo >> 8) & 0xff;
+       printk(KERN_INFO "eps: Current multiplier = %d\n",
+               current_multiplier);
+
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
        return err;
 }
@@ -141,9 +152,10 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
        u8 current_multiplier, current_voltage;
        u8 max_multiplier, max_voltage;
        u8 min_multiplier, min_voltage;
-       u8 brand;
+       u8 brand = 0;
        u32 fsb;
        struct eps_cpu_data *centaur;
+       struct cpuinfo_x86 *c = &cpu_data(0);
        struct cpufreq_frequency_table *f_table;
        int k, step, voltage;
        int ret;
@@ -153,21 +165,36 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
                return -ENODEV;
 
        /* Check brand */
-       printk("eps: Detected VIA ");
-       rdmsr(0x1153, lo, hi);
-       brand = (((lo >> 2) ^ lo) >> 18) & 3;
+       printk(KERN_INFO "eps: Detected VIA ");
+
+       switch (c->x86_model) {
+       case 10:
+               rdmsr(0x1153, lo, hi);
+               brand = (((lo >> 2) ^ lo) >> 18) & 3;
+               printk(KERN_CONT "Model A ");
+               break;
+       case 13:
+               rdmsr(0x1154, lo, hi);
+               brand = (((lo >> 4) ^ (lo >> 2))) & 0x000000ff;
+               printk(KERN_CONT "Model D ");
+               break;
+       }
+
        switch(brand) {
        case EPS_BRAND_C7M:
-               printk("C7-M\n");
+               printk(KERN_CONT "C7-M\n");
                break;
        case EPS_BRAND_C7:
-               printk("C7\n");
+               printk(KERN_CONT "C7\n");
                break;
        case EPS_BRAND_EDEN:
-               printk("Eden\n");
+               printk(KERN_CONT "Eden\n");
+               break;
+       case EPS_BRAND_C7D:
+               printk(KERN_CONT "C7-D\n");
                break;
        case EPS_BRAND_C3:
-               printk("C3\n");
+               printk(KERN_CONT "C3\n");
                return -ENODEV;
                break;
        }
@@ -179,7 +206,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
                /* Can be locked at 0 */
                rdmsrl(MSR_IA32_MISC_ENABLE, val);
                if (!(val & 1 << 16)) {
-                       printk("eps: Can't enable Enhanced PowerSaver\n");
+                       printk(KERN_INFO "eps: Can't enable Enhanced PowerSaver\n");
                        return -ENODEV;
                }
        }
@@ -187,19 +214,19 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
        /* Print voltage and multiplier */
        rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
        current_voltage = lo & 0xff;
-       printk("eps: Current voltage = %dmV\n", current_voltage * 16 + 700);
+       printk(KERN_INFO "eps: Current voltage = %dmV\n", current_voltage * 16 + 700);
        current_multiplier = (lo >> 8) & 0xff;
-       printk("eps: Current multiplier = %d\n", current_multiplier);
+       printk(KERN_INFO "eps: Current multiplier = %d\n", current_multiplier);
 
        /* Print limits */
        max_voltage = hi & 0xff;
-       printk("eps: Highest voltage = %dmV\n", max_voltage * 16 + 700);
+       printk(KERN_INFO "eps: Highest voltage = %dmV\n", max_voltage * 16 + 700);
        max_multiplier = (hi >> 8) & 0xff;
-       printk("eps: Highest multiplier = %d\n", max_multiplier);
+       printk(KERN_INFO "eps: Highest multiplier = %d\n", max_multiplier);
        min_voltage = (hi >> 16) & 0xff;
-       printk("eps: Lowest voltage = %dmV\n", min_voltage * 16 + 700);
+       printk(KERN_INFO "eps: Lowest voltage = %dmV\n", min_voltage * 16 + 700);
        min_multiplier = (hi >> 24) & 0xff;
-       printk("eps: Lowest multiplier = %d\n", min_multiplier);
+       printk(KERN_INFO "eps: Lowest multiplier = %d\n", min_multiplier);
 
        /* Sanity checks */
        if (current_multiplier == 0 || max_multiplier == 0
@@ -208,7 +235,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
        if (current_multiplier > max_multiplier
            || max_multiplier <= min_multiplier)
                return -EINVAL;
-       if (current_voltage > 0x1c || max_voltage > 0x1c)
+       if (current_voltage > 0x1f || max_voltage > 0x1f)
                return -EINVAL;
        if (max_voltage < min_voltage)
                return -EINVAL;
@@ -310,7 +337,7 @@ static int __init eps_init(void)
        /* This driver will work only on Centaur C7 processors with
         * Enhanced SpeedStep/PowerSaver registers */
        if (c->x86_vendor != X86_VENDOR_CENTAUR
-           || c->x86 != 6 || c->x86_model != 10)
+           || c->x86 != 6 || c->x86_model < 10)
                return -ENODEV;
        if (!cpu_has(c, X86_FEATURE_EST))
                return -ENODEV;
index 2ed7db2fd257b3a25c78dd61dd48683bb60a49f7..9d9eae82e60fae3baec7333269ddb6c46b7d1d27 100644 (file)
@@ -181,8 +181,8 @@ static __init struct pci_dev *gx_detect_chipset(void)
        struct pci_dev *gx_pci = NULL;
 
        /* check if CPU is a MediaGX or a Geode. */
-       if ((current_cpu_data.x86_vendor != X86_VENDOR_NSC) &&
-           (current_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) {
+       if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) &&
+           (boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) {
                dprintk("error: no MediaGX/Geode processor found!\n");
                return NULL;
        }
index b5a9863d6cdc336ce7b13f5c9d797944b179cbc6..0a61159d7b71389c8e8bcdbae7b913463b0f318c 100644 (file)
@@ -460,7 +460,7 @@ static int powernow_decode_bios (int maxfid, int startvid)
 
                        latency = psb->settlingtime;
                        if (latency < 100) {
-                               printk (KERN_INFO PFX "BIOS set settling time to %d microseconds."
+                               printk(KERN_INFO PFX "BIOS set settling time to %d microseconds. "
                                                "Should be at least 100. Correcting.\n", latency);
                                latency = 100;
                        }
index 5affe91ca1e5964ff9bd309c78c3619f04379c7b..c99d59d8ef2ea46694ac8b3da1cb07de2714cf10 100644 (file)
@@ -578,10 +578,9 @@ static void print_basics(struct powernow_k8_data *data)
        for (j = 0; j < data->numps; j++) {
                if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID) {
                        if (cpu_family == CPU_HW_PSTATE) {
-                               printk(KERN_INFO PFX "   %d : fid 0x%x did 0x%x (%d MHz)\n",
+                               printk(KERN_INFO PFX "   %d : pstate %d (%d MHz)\n",
                                        j,
-                                       (data->powernow_table[j].index & 0xff00) >> 8,
-                                       (data->powernow_table[j].index & 0xff0000) >> 16,
+                                       data->powernow_table[j].index,
                                        data->powernow_table[j].frequency/1000);
                        } else {
                                printk(KERN_INFO PFX "   %d : fid 0x%x (%d MHz), vid 0x%x\n",
@@ -1235,8 +1234,10 @@ static unsigned int powernowk8_get (unsigned int cpu)
        struct powernow_k8_data *data;
        cpumask_t oldmask = current->cpus_allowed;
        unsigned int khz = 0;
+       unsigned int first;
 
-       data = per_cpu(powernow_data, first_cpu(per_cpu(cpu_core_map, cpu)));
+       first = first_cpu(per_cpu(cpu_core_map, cpu));
+       data = per_cpu(powernow_data, first);
 
        if (!data)
                return -EINVAL;
index afd2b520d35c6258a25a2bc0f804279b647ae430..ab48cfed4d96ce5629e29f3a21ffd9c3e25d8a21 100644 (file)
@@ -47,7 +47,7 @@ struct powernow_k8_data {
 #define CPUID_XFAM                     0x0ff00000      /* extended family */
 #define CPUID_XFAM_K8                  0
 #define CPUID_XMOD                     0x000f0000      /* extended model */
-#define CPUID_XMOD_REV_MASK            0x00080000
+#define CPUID_XMOD_REV_MASK            0x000c0000
 #define CPUID_XFAM_10H                 0x00100000      /* family 0x10 */
 #define CPUID_USE_XFAM_XMOD            0x00000f00
 #define CPUID_GET_MAX_CAPABILITIES     0x80000000
index 76c3ab0da468db354af1d55da7f5b5af39fdca50..98d4fdb7dc046b73cfc00402be21da9a9d303686 100644 (file)
@@ -189,10 +189,7 @@ static unsigned int pentium4_get_frequency(void)
                printk(KERN_DEBUG "speedstep-lib: couldn't detect FSB speed. Please send an e-mail to <linux@brodo.de>\n");
 
        /* Multiplier. */
-       if (c->x86_model < 2)
-               mult = msr_lo >> 27;
-       else
-               mult = msr_lo >> 24;
+       mult = msr_lo >> 24;
 
        dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult));
 
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 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 2bf6903cb4448d8152f0c671f3c0d2bdae0afae7..b72e61359c365720a0c65c30af8be4e0b404cf52 100644 (file)
@@ -274,7 +274,7 @@ int __init get_memcfg_from_srat(void)
        int tables = 0;
        int i = 0;
 
-       rsdp_address = acpi_find_rsdp();
+       rsdp_address = acpi_os_get_root_pointer();
        if (!rsdp_address) {
                printk("%s: System description tables not found\n",
                       __FUNCTION__);
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 9b61c75a23556f76898ca2f8b1d26d71b206ca26..5fe880fc305d03c90131948bab8c4cd16096e9f9 100644 (file)
@@ -644,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 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 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 d74d9fbb9fd21177eca9f2096d8df82fc4f2b469..b86877bdc7ac50ede83ed0e311c52e692548ef3f 100644 (file)
@@ -60,6 +60,8 @@ source "drivers/power/Kconfig"
 
 source "drivers/hwmon/Kconfig"
 
+source "drivers/thermal/Kconfig"
+
 source "drivers/watchdog/Kconfig"
 
 source "drivers/ssb/Kconfig"
index f1c11db52a57e09b30b13380b1b000923dafcf3b..30ba97ec5eb525eefd89807600490c7f0dac0854 100644 (file)
@@ -65,6 +65,7 @@ obj-y                         += i2c/
 obj-$(CONFIG_W1)               += w1/
 obj-$(CONFIG_POWER_SUPPLY)     += power/
 obj-$(CONFIG_HWMON)            += hwmon/
+obj-$(CONFIG_THERMAL)          += thermal/
 obj-$(CONFIG_WATCHDOG)         += watchdog/
 obj-$(CONFIG_PHONE)            += telephony/
 obj-$(CONFIG_MD)               += md/
index ccf6ea95f68c76dc27d5eb9f06b15e3cd384d9d6..7ef172c2a1d64cd3c641b631efff4e5946cc75b1 100644 (file)
@@ -68,26 +68,28 @@ config ACPI_PROCFS
 
          Say N to delete /proc/acpi/ files that have moved to /sys/
 config ACPI_PROCFS_POWER
-       bool "Deprecated power /proc/acpi folders"
+       bool "Deprecated power /proc/acpi directories"
        depends on PROC_FS
        default y
        ---help---
          For backwards compatibility, this option allows
-          deprecated power /proc/acpi/ folders to exist, even when
+          deprecated power /proc/acpi/ directories to exist, even when
           they have been replaced by functions in /sys.
-          The deprecated folders (and their replacements) include:
+          The deprecated directories (and their replacements) include:
          /proc/acpi/battery/* (/sys/class/power_supply/*)
          /proc/acpi/ac_adapter/* (sys/class/power_supply/*)
-         This option has no effect on /proc/acpi/ folders
+         This option has no effect on /proc/acpi/ directories
          and functions, which do not yet exist in /sys
 
-         Say N to delete power /proc/acpi/ folders that have moved to /sys/
+         Say N to delete power /proc/acpi/ directories that have moved to /sys/
+
 config ACPI_SYSFS_POWER
        bool "Future power /sys interface"
        select POWER_SUPPLY
        default y
        ---help---
          Say N to disable power /sys interface
+
 config ACPI_PROC_EVENT
        bool "Deprecated /proc/acpi/event support"
        depends on PROC_FS
@@ -186,6 +188,7 @@ config ACPI_HOTPLUG_CPU
 config ACPI_THERMAL
        tristate "Thermal Zone"
        depends on ACPI_PROCESSOR
+       select THERMAL
        default y
        help
          This driver adds support for ACPI thermal zones.  Most mobile and
@@ -199,6 +202,16 @@ config ACPI_NUMA
        depends on (X86 || IA64)
        default y if IA64_GENERIC || IA64_SGI_SN2
 
+config ACPI_WMI
+       tristate "WMI (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       help
+         This driver adds support for the ACPI-WMI mapper device (PNP0C14)
+         found on some systems.
+
+         NOTE: You will need another driver or userspace application on top of
+         this to actually use anything defined in the ACPI-WMI mapper.
+
 config ACPI_ASUS
         tristate "ASUS/Medion Laptop Extras"
        depends on X86
@@ -263,8 +276,10 @@ config ACPI_CUSTOM_DSDT
        depends on !STANDALONE
        default n 
        help
-         This option is to load a custom ACPI DSDT
-         If you don't know what that is, say N.
+         This option supports a custom DSDT by linking it into the kernel.
+         See Documentation/acpi/dsdt-override.txt
+
+         If unsure, say N.
 
 config ACPI_CUSTOM_DSDT_FILE
        string "Custom DSDT Table file to include"
@@ -274,6 +289,17 @@ config ACPI_CUSTOM_DSDT_FILE
          Enter the full path name to the file which includes the AmlCode
          declaration.
 
+config ACPI_CUSTOM_DSDT_INITRD
+       bool "Read Custom DSDT from initramfs"
+       depends on BLK_DEV_INITRD
+       default n
+       help
+         This option supports a custom DSDT by optionally loading it from initrd.
+         See Documentation/acpi/dsdt-override.txt
+
+         If you are not using this feature now, but may use it later,
+         it is safe to say Y here.
+
 config ACPI_BLACKLIST_YEAR
        int "Disable ACPI for systems before Jan 1st this year" if X86_32
        default 0
index 456446f9007780eac345479b5fc9d173ddfdbe7c..f29812a86533778a28b211b5c601bcf4863fadc9 100644 (file)
@@ -55,6 +55,7 @@ obj-$(CONFIG_ACPI_THERMAL)    += thermal.o
 obj-$(CONFIG_ACPI_SYSTEM)      += system.o event.o
 obj-$(CONFIG_ACPI_DEBUG)       += debug.o
 obj-$(CONFIG_ACPI_NUMA)                += numa.o
+obj-$(CONFIG_ACPI_WMI)         += wmi.o
 obj-$(CONFIG_ACPI_ASUS)                += asus_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
 obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)      += acpi_memhotplug.o
index d915fec9bf63e8c1f085dff9ea18f36f1b7ce20d..d25ef961415cefdeebab67ac29f5a5f49d87ff18 100644 (file)
@@ -142,6 +142,7 @@ struct asus_hotk {
                xxN,            //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
                A4S,            //Z81sp
                //(Centrino)
+               F3Sa,
                END_MODEL
        } model;                //Models currently supported
        u16 event_count[128];   //count for each event TODO make this better
@@ -405,7 +406,20 @@ static struct model_data model_conf[END_MODEL] = {
                .brightness_get    = "GPLV",
                .mt_bt_switch      = "BLED",
                .mt_wled           = "WLED"
-       }
+       },
+
+       {
+               .name           = "F3Sa",
+               .mt_bt_switch   = "BLED",
+               .mt_wled        = "WLED",
+               .mt_mled        = "MLED",
+               .brightness_get = "GPLV",
+               .brightness_set = "SPLV",
+               .mt_lcd_switch  = "\\_SB.PCI0.SBRG.EC0._Q10",
+               .lcd_status     = "\\_SB.PCI0.SBRG.EC0.RPIN",
+               .display_get    = "\\ADVG",
+               .display_set    = "SDSP",
+       },
 
 };
 
@@ -710,15 +724,8 @@ static int get_lcd_state(void)
 {
        int lcd = 0;
 
-       if (hotk->model != L3H) {
-               /* We don't have to check anything if we are here */
-               if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error reading LCD status\n");
-
-               if (hotk->model == L2D)
-                       lcd = ~lcd;
-       } else {                /* L3H and the like have to be handled differently */
+       if (hotk->model == L3H) {
+               /* L3H and the like have to be handled differently */
                acpi_status status = 0;
                struct acpi_object_list input;
                union acpi_object mt_params[2];
@@ -745,6 +752,32 @@ static int get_lcd_state(void)
                if (out_obj.type == ACPI_TYPE_INTEGER)
                        /* That's what the AML code does */
                        lcd = out_obj.integer.value >> 8;
+       } else if (hotk->model == F3Sa) {
+               unsigned long tmp;
+               union acpi_object param;
+               struct acpi_object_list input;
+               acpi_status status;
+
+               /* Read pin 11 */
+               param.type = ACPI_TYPE_INTEGER;
+               param.integer.value = 0x11;
+               input.count = 1;
+               input.pointer = &param;
+
+               status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
+                                               &input, &tmp);
+               if (status != AE_OK)
+                       return -1;
+
+               lcd = tmp;
+       } else {
+               /* We don't have to check anything if we are here */
+               if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
+                       printk(KERN_WARNING
+                              "Asus ACPI: Error reading LCD status\n");
+
+               if (hotk->model == L2D)
+                       lcd = ~lcd;
        }
 
        return (lcd & 1);
@@ -1134,6 +1167,8 @@ static int asus_model_match(char *model)
                return W5A;
        else if (strncmp(model, "A4S", 3) == 0)
                return A4S;
+       else if (strncmp(model, "F3Sa", 4) == 0)
+               return F3Sa;
        else
                return END_MODEL;
 }
index c4a769d1ba8542bf0210f71eb6930641c9062a2f..f6215e8098086887f11b414e180923479949c467 100644 (file)
@@ -194,6 +194,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_MANUFACTURER:
                val->strval = battery->oem_info;
                break;
+       case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+               val->strval = battery->serial_number;
+               break;
        default:
                return -EINVAL;
        }
@@ -212,6 +215,7 @@ static enum power_supply_property charge_battery_props[] = {
        POWER_SUPPLY_PROP_CHARGE_NOW,
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
+       POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 
 static enum power_supply_property energy_battery_props[] = {
@@ -226,6 +230,7 @@ static enum power_supply_property energy_battery_props[] = {
        POWER_SUPPLY_PROP_ENERGY_NOW,
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
+       POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 #endif
 
index 6daf6088ac888329177f35e4f7258bc8dfa42ddb..1fa86811b8ee6ee8e5e675666fc1092f0b4c6eb5 100644 (file)
@@ -46,6 +46,12 @@ MODULE_LICENSE("GPL");
        printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
 static void bay_notify(acpi_handle handle, u32 event, void *data);
 
+static const struct acpi_device_id bay_device_ids[] = {
+       {"LNXIOBAY", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, bay_device_ids);
+
 struct bay {
        acpi_handle handle;
        char *name;
@@ -128,7 +134,7 @@ static ssize_t show_present(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
 
 }
-DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
+static DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
 
 /*
  * write_eject - write method for "eject" file in sysfs
@@ -144,7 +150,7 @@ static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
        eject_device(bay->handle);
        return count;
 }
-DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
+static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
 
 /**
  * is_ata - see if a device is an ata device
index 8809654d6cc965e292b2424f5f85cdecca15c1a2..6dbaa2d15fe0fb1b698cb6c8e1d11841f76b813e 100644 (file)
@@ -70,8 +70,6 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
        /* IBM 600E - _ADR should return 7, but it returns 1 */
        {"IBM   ", "TP600E  ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
         "Incorrect _ADR", 1},
-       {"ASUS\0\0", "P2B-S   ", 0, ACPI_SIG_DSDT, all_versions,
-        "Bogus PCI routing", 1},
 
        {""}
 };
@@ -208,33 +206,35 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
         * Disable OSI(Linux) warnings on all "Acer, inc."
         *
         * _OSI(Linux) disables the latest Windows BIOS code:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
         * _OSI(Linux) effect unknown:
         * DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
         */
-       {
-       .callback = dmi_disable_osi_linux,
-       .ident = "Acer, inc.",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."),
-               },
-       },
+       /*
+        * note that dmi_check_system() uses strstr()
+        * to match sub-strings rather than !strcmp(),
+        * so "Acer" below matches "Acer, inc." above.
+        */
        /*
         * Disable OSI(Linux) warnings on all "Acer"
         *
         * _OSI(Linux) effect unknown:
-        * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
+        *
+        * _OSI(Linux) is a NOP:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
         */
        {
-       .callback = dmi_unknown_osi_linux,
+       .callback = dmi_disable_osi_linux,
        .ident = "Acer",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -242,21 +242,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        },
        /*
         * Disable OSI(Linux) warnings on all "Apple Computer, Inc."
+        * Disable OSI(Linux) warnings on all "Apple Inc."
         *
         * _OSI(Linux) confirmed to be a NOP:
         * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
         * _OSI(Linux) effect unknown:
         * DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
         * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
-        * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
         */
        {
        .callback = dmi_disable_osi_linux,
        .ident = "Apple",
        .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
+                    DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
                },
        },
        /*
@@ -294,13 +295,13 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
         * DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
         */
        {
-       .callback = dmi_unknown_osi_linux,
+       .callback = dmi_disable_osi_linux,
        .ident = "Compal",
        .matches = {
                     DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
                },
        },
-       { /* OSI(Linux) touches USB, breaks suspend to disk */
+       { /* OSI(Linux) touches USB, unknown side-effect */
        .callback = dmi_disable_osi_linux,
        .ident = "Dell Dimension 5150",
        .matches = {
@@ -310,7 +311,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        },
        { /* OSI(Linux) is a NOP */
        .callback = dmi_disable_osi_linux,
-       .ident = "Dell",
+       .ident = "Dell i1501",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                     DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"),
@@ -318,7 +319,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        },
        { /* OSI(Linux) effect unknown */
        .callback = dmi_unknown_osi_linux,
-       .ident = "Dell",
+       .ident = "Dell Latitude D830",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                     DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"),
@@ -326,7 +327,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        },
        { /* OSI(Linux) effect unknown */
        .callback = dmi_unknown_osi_linux,
-       .ident = "Dell",
+       .ident = "Dell OP GX620",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                     DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"),
@@ -334,15 +335,23 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        },
        { /* OSI(Linux) effect unknown */
        .callback = dmi_unknown_osi_linux,
-       .ident = "Dell",
+       .ident = "Dell PE 1900",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                     DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"),
                },
        },
+       { /* OSI(Linux) is a NOP */
+       .callback = dmi_disable_osi_linux,
+       .ident = "Dell PE R200",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R200"),
+               },
+       },
        { /* OSI(Linux) touches USB */
        .callback = dmi_disable_osi_linux,
-       .ident = "Dell",
+       .ident = "Dell PR 390",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                     DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"),
@@ -358,7 +367,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        },
        { /* OSI(Linux) effect unknown */
        .callback = dmi_unknown_osi_linux,
-       .ident = "Dell",
+       .ident = "Dell PE SC440",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                     DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"),
@@ -474,6 +483,11 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
         *
         * _OSI(Linux) confirmed to be a NOP:
         * DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"),
+        * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
+        *
+        * unknown:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "S1-MDGDG"),
+        * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
         */
        {
        .callback = dmi_disable_osi_linux,
@@ -516,7 +530,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
         * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
         */
        {
-       .callback = dmi_unknown_osi_linux,
+       .callback = dmi_disable_osi_linux,
        .ident = "Sony",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
index 1b4cf984b081d0f0a697d139d1df0c1d281fe31e..8b0d4b7d188a4b2cae701f50459cd80f39fd4a63 100644 (file)
@@ -122,6 +122,31 @@ int acpi_bus_get_status(struct acpi_device *device)
 
 EXPORT_SYMBOL(acpi_bus_get_status);
 
+void acpi_bus_private_data_handler(acpi_handle handle,
+                                  u32 function, void *context)
+{
+       return;
+}
+EXPORT_SYMBOL(acpi_bus_private_data_handler);
+
+int acpi_bus_get_private_data(acpi_handle handle, void **data)
+{
+       acpi_status status = AE_OK;
+
+       if (!*data)
+               return -EINVAL;
+
+       status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
+       if (ACPI_FAILURE(status) || !*data) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
+                               handle));
+               return -ENODEV;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(acpi_bus_get_private_data);
+
 /* --------------------------------------------------------------------------
                                  Power Management
    -------------------------------------------------------------------------- */
@@ -366,7 +391,6 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
        return 0;
 }
 
-EXPORT_SYMBOL(acpi_bus_receive_event);
 #endif /* CONFIG_ACPI_PROC_EVENT */
 
 /* --------------------------------------------------------------------------
index bf513e07b7735738c0099171443ac05e6fcc917e..6df564f4ca6ed4bf48c1284f3c7d2807986b1f77 100644 (file)
@@ -130,6 +130,63 @@ static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
 module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
 module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
 
+static char trace_method_name[6];
+module_param_string(trace_method_name, trace_method_name, 6, 0644);
+static unsigned int trace_debug_layer;
+module_param(trace_debug_layer, uint, 0644);
+static unsigned int trace_debug_level;
+module_param(trace_debug_level, uint, 0644);
+
+static int param_set_trace_state(const char *val, struct kernel_param *kp)
+{
+       int result = 0;
+
+       if (!strncmp(val, "enable", strlen("enable") - 1)) {
+               result = acpi_debug_trace(trace_method_name, trace_debug_level,
+                                         trace_debug_layer, 0);
+               if (result)
+                       result = -EBUSY;
+               goto exit;
+       }
+
+       if (!strncmp(val, "disable", strlen("disable") - 1)) {
+               int name = 0;
+               result = acpi_debug_trace((char *)&name, trace_debug_level,
+                                         trace_debug_layer, 0);
+               if (result)
+                       result = -EBUSY;
+               goto exit;
+       }
+
+       if (!strncmp(val, "1", 1)) {
+               result = acpi_debug_trace(trace_method_name, trace_debug_level,
+                                         trace_debug_layer, 1);
+               if (result)
+                       result = -EBUSY;
+               goto exit;
+       }
+
+       result = -EINVAL;
+exit:
+       return result;
+}
+
+static int param_get_trace_state(char *buffer, struct kernel_param *kp)
+{
+       if (!acpi_gbl_trace_method_name)
+               return sprintf(buffer, "disable");
+       else {
+               if (acpi_gbl_trace_flags & 1)
+                       return sprintf(buffer, "1");
+               else
+                       return sprintf(buffer, "enable");
+       }
+       return 0;
+}
+
+module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
+                 NULL, 0644);
+
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
index fc9da4879cbfb932e3b2e8ea683b12835d2391ad..f501e083aac78779c6f5a0f4f0012bc505f6d6b1 100644 (file)
@@ -359,7 +359,9 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
 
        status = acpi_os_validate_address(obj_desc->region.space_id,
                                          obj_desc->region.address,
-                                         (acpi_size) obj_desc->region.length);
+                                         (acpi_size) obj_desc->region.length,
+                                         acpi_ut_get_node_name(node));
+
        if (ACPI_FAILURE(status)) {
                /*
                 * Invalid address/length. We will emit an error message and mark
index 1dabdf4c07b36308e4ece7f7f3a0497ee4bb0c1c..307cef65c24758bacb00ef7a2700fcb96a29738b 100644 (file)
@@ -51,6 +51,12 @@ static struct atomic_notifier_head dock_notifier_list;
 static struct platform_device *dock_device;
 static char dock_device_name[] = "dock";
 
+static const struct acpi_device_id dock_device_ids[] = {
+       {"LNXDOCK", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, dock_device_ids);
+
 struct dock_station {
        acpi_handle handle;
        unsigned long last_dock_time;
@@ -680,7 +686,7 @@ static ssize_t show_docked(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
 
 }
-DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
+static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
 
 /*
  * show_flags - read method for flags file in sysfs
@@ -691,7 +697,7 @@ static ssize_t show_flags(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
 
 }
-DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
 
 /*
  * write_undock - write method for "undock" file in sysfs
@@ -707,7 +713,7 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
        ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
        return ret ? ret: count;
 }
-DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
+static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
 
 /*
  * show_dock_uid - read method for "uid" file in sysfs
@@ -723,7 +729,7 @@ static ssize_t show_dock_uid(struct device *dev,
 
        return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
 }
-DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
+static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
 
 /**
  * dock_add - add a new dock station
index 987b967c74670728831af322571e4a182fb84d7e..7222a18a03198d0bc70121d1246dc27af1d0629e 100644 (file)
@@ -573,7 +573,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
                      void *handler_context, void *region_context)
 {
        struct acpi_ec *ec = handler_context;
-       int result = 0, i = 0;
+       int result = 0, i;
        u8 temp = 0;
 
        if ((address > 0xFF) || !value || !handler_context)
@@ -585,7 +585,18 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
        if (bits != 8 && acpi_strict)
                return AE_BAD_PARAMETER;
 
-       while (bits - i > 0) {
+       acpi_ec_burst_enable(ec);
+
+       if (function == ACPI_READ) {
+               result = acpi_ec_read(ec, address, &temp);
+               *value = temp;
+       } else {
+               temp = 0xff & (*value);
+               result = acpi_ec_write(ec, address, temp);
+       }
+
+       for (i = 8; unlikely(bits - i > 0); i += 8) {
+               ++address;
                if (function == ACPI_READ) {
                        result = acpi_ec_read(ec, address, &temp);
                        (*value) |= ((acpi_integer)temp) << i;
@@ -593,10 +604,10 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
                        temp = 0xff & ((*value) >> i);
                        result = acpi_ec_write(ec, address, temp);
                }
-               i += 8;
-               ++address;
        }
 
+       acpi_ec_burst_disable(ec);
+
        switch (result) {
        case -EINVAL:
                return AE_BAD_PARAMETER;
index 5c95863f8fa9f324c0b98d88cd40f96eb16f9ead..5479dc0eeeecdfe6401d0d81fd435af69ac67e42 100644 (file)
@@ -109,6 +109,34 @@ static const struct file_operations acpi_system_event_ops = {
 };
 #endif /* CONFIG_ACPI_PROC_EVENT */
 
+/* ACPI notifier chain */
+BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
+
+int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
+{
+       struct acpi_bus_event event;
+
+       strcpy(event.device_class, dev->pnp.device_class);
+       strcpy(event.bus_id, dev->pnp.bus_id);
+       event.type = type;
+       event.data = data;
+       return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
+                        == NOTIFY_BAD) ? -EINVAL : 0;
+}
+EXPORT_SYMBOL(acpi_notifier_call_chain);
+
+int register_acpi_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&acpi_chain_head, nb);
+}
+EXPORT_SYMBOL(register_acpi_notifier);
+
+int unregister_acpi_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
+}
+EXPORT_SYMBOL(unregister_acpi_notifier);
+
 #ifdef CONFIG_NET
 static unsigned int acpi_event_seqnum;
 struct acpi_genl_event {
index e41287815ea1c864176ad507110ff88a4eaf2894..3048801a37b5e1e91dfd6a7595b560cfe27531c2 100644 (file)
@@ -259,7 +259,7 @@ u32 acpi_ev_fixed_event_detect(void)
                        enable_bit_mask)) {
 
                        /* Found an active (signalled) event */
-
+                       acpi_os_fixed_event_count(i);
                        int_status |= acpi_ev_fixed_event_dispatch((u32) i);
                }
        }
index e22f4a973c0fdc4d4cf5670e8ace14d83e75abe1..0dadd2adc8001a109669b4ae62c673da60f4747b 100644 (file)
@@ -270,18 +270,18 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
        case ACPI_GPE_TYPE_WAKE_RUN:
                ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
 
-               /*lint -fallthrough */
+               /* fallthrough */
 
        case ACPI_GPE_TYPE_RUNTIME:
 
                /* Disable the requested runtime GPE */
 
                ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
-               status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
-               break;
+
+               /* fallthrough */
 
        default:
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+               acpi_hw_write_gpe_enable_reg(gpe_event_info);
        }
 
        return_ACPI_STATUS(AE_OK);
@@ -501,6 +501,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
  *              an interrupt handler.
  *
  ******************************************************************************/
+static void acpi_ev_asynch_enable_gpe(void *context);
 
 static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
 {
@@ -576,22 +577,30 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
                                         method_node)));
                }
        }
+       /* Defer enabling of GPE until all notify handlers are done */
+       acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
+                               gpe_event_info);
+       return_VOID;
+}
 
-       if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
+static void acpi_ev_asynch_enable_gpe(void *context)
+{
+       struct acpi_gpe_event_info *gpe_event_info = context;
+       acpi_status status;
+       if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
            ACPI_GPE_LEVEL_TRIGGERED) {
                /*
                 * GPE is level-triggered, we clear the GPE status bit after
                 * handling the event.
                 */
-               status = acpi_hw_clear_gpe(&local_gpe_event_info);
+               status = acpi_hw_clear_gpe(gpe_event_info);
                if (ACPI_FAILURE(status)) {
                        return_VOID;
                }
        }
 
        /* Enable this GPE */
-
-       (void)acpi_hw_write_gpe_enable_reg(&local_gpe_event_info);
+       (void)acpi_hw_write_gpe_enable_reg(gpe_event_info);
        return_VOID;
 }
 
@@ -618,7 +627,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
 
        ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
 
-       acpi_gpe_count++;
+       acpi_os_gpe_count(gpe_number);
 
        /*
         * If edge-triggered, clear the GPE status bit now.  Note that
index a6e149d692cbd332aaf947d689815392474cda34..48cb705b274afb837129ae6d13ead27f8f2c6ccc 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
-
+#include <linux/thermal.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -68,9 +68,55 @@ static struct acpi_driver acpi_fan_driver = {
                },
 };
 
+/* thermal cooling device callbacks */
+static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+{
+       /* ACPI fan device only support two states: ON/OFF */
+       return sprintf(buf, "1\n");
+}
+
+static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+{
+       struct acpi_device *device = cdev->devdata;
+       int state;
+       int result;
+
+       if (!device)
+               return -EINVAL;
+
+       result = acpi_bus_get_power(device->handle, &state);
+       if (result)
+               return result;
+
+       return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
+                        (state == ACPI_STATE_D0 ? "1" : "unknown"));
+}
+
+static int
+fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+{
+       struct acpi_device *device = cdev->devdata;
+       int result;
+
+       if (!device || (state != 0 && state != 1))
+               return -EINVAL;
+
+       result = acpi_bus_set_power(device->handle,
+                               state ? ACPI_STATE_D0 : ACPI_STATE_D3);
+
+       return result;
+}
+
+static struct thermal_cooling_device_ops fan_cooling_ops = {
+       .get_max_state = fan_get_max_state,
+       .get_cur_state = fan_get_cur_state,
+       .set_cur_state = fan_set_cur_state,
+};
+
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
 
 static struct proc_dir_entry *acpi_fan_dir;
 
@@ -171,7 +217,17 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
 
        return 0;
 }
+#else
+static int acpi_fan_add_fs(struct acpi_device *device)
+{
+       return 0;
+}
 
+static int acpi_fan_remove_fs(struct acpi_device *device)
+{
+       return 0;
+}
+#endif
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -179,9 +235,8 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
 static int acpi_fan_add(struct acpi_device *device)
 {
        int result = 0;
-       struct acpi_fan *fan = NULL;
        int state = 0;
-
+       struct thermal_cooling_device *cdev;
 
        if (!device)
                return -EINVAL;
@@ -199,6 +254,25 @@ static int acpi_fan_add(struct acpi_device *device)
        acpi_bus_set_power(device->handle, state);
        device->flags.force_power_state = 0;
 
+       cdev = thermal_cooling_device_register("Fan", device,
+                                               &fan_cooling_ops);
+       if (cdev)
+               printk(KERN_INFO PREFIX
+                       "%s is registered as cooling_device%d\n",
+                       device->dev.bus_id, cdev->id);
+       else
+               goto end;
+       acpi_driver_data(device) = cdev;
+       result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj,
+                                       "thermal_cooling");
+       if (result)
+               return result;
+
+       result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj,
+                                       "device");
+        if (result)
+                return result;
+
        result = acpi_fan_add_fs(device);
        if (result)
                goto end;
@@ -208,18 +282,20 @@ static int acpi_fan_add(struct acpi_device *device)
               !device->power.state ? "on" : "off");
 
       end:
-       if (result)
-               kfree(fan);
-
        return result;
 }
 
 static int acpi_fan_remove(struct acpi_device *device, int type)
 {
-       if (!device || !acpi_driver_data(device))
+       struct thermal_cooling_device *cdev = acpi_driver_data(device);
+
+       if (!device || !cdev)
                return -EINVAL;
 
        acpi_fan_remove_fs(device);
+       sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+       sysfs_remove_link(&cdev->device.kobj, "device");
+       thermal_cooling_device_unregister(cdev);
 
        return 0;
 }
@@ -261,10 +337,12 @@ static int __init acpi_fan_init(void)
        int result = 0;
 
 
+#ifdef CONFIG_ACPI_PROCFS
        acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
        if (!acpi_fan_dir)
                return -ENODEV;
        acpi_fan_dir->owner = THIS_MODULE;
+#endif
 
        result = acpi_bus_register_driver(&acpi_fan_driver);
        if (result < 0) {
index 4893e256e399bea43ee35a62a0c0fa16667d3bdf..eda0978b57c6946b9580ab24869794a2bc14b2bd 100644 (file)
@@ -36,8 +36,6 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
        return -ENODEV;
 }
 
-EXPORT_SYMBOL(register_acpi_bus_type);
-
 int unregister_acpi_bus_type(struct acpi_bus_type *type)
 {
        if (acpi_disabled)
@@ -53,8 +51,6 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type)
        return -ENODEV;
 }
 
-EXPORT_SYMBOL(unregister_acpi_bus_type);
-
 static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
 {
        struct acpi_bus_type *tmp, *ret = NULL;
index fd1c4ba63367469f9826460c6b545407491f9f86..058d0be5cbe2983ee747ead0f40b396bfd8f9b66 100644 (file)
@@ -286,13 +286,13 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
        }
 
        /*
+        * 1) Disable/Clear all GPEs
         * 2) Enable all wakeup GPEs
         */
        status = acpi_hw_disable_all_gpes();
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
-
        acpi_gbl_system_awake_and_running = FALSE;
 
        status = acpi_hw_enable_all_wakeup_gpes();
index f39fbc6b9237687a3ffd0c1b387499bb6ad0714c..b92133faf5b7087fde85829c3511a64d3b24afb3 100644 (file)
@@ -443,6 +443,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
        struct acpica_device_id hid;
        struct acpi_compatible_id_list *cid;
        acpi_native_uint i;
+       int found;
 
        status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
        if (ACPI_FAILURE(status)) {
@@ -496,16 +497,19 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
 
                        /* Walk the CID list */
 
+                       found = 0;
                        for (i = 0; i < cid->count; i++) {
                                if (ACPI_STRNCMP(cid->id[i].value, info->hid,
                                                 sizeof(struct
-                                                       acpi_compatible_id)) !=
+                                                       acpi_compatible_id)) ==
                                    0) {
-                                       ACPI_FREE(cid);
-                                       return (AE_OK);
+                                       found = 1;
+                                       break;
                                }
                        }
                        ACPI_FREE(cid);
+                       if (!found)
+                               return (AE_OK);
                }
        }
 
index 0822d9fc1cb4ef7d0ea2dbf69873505fef1cc41d..5d59cb33b1a5435ba16052b032a9f8c24da15e1a 100644 (file)
@@ -78,6 +78,7 @@ int acpi_map_pxm_to_node(int pxm)
        return node;
 }
 
+#if 0
 void __cpuinit acpi_unmap_pxm_to_node(int node)
 {
        int pxm = node_to_pxm_map[node];
@@ -85,6 +86,7 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
        node_to_pxm_map[node] = PXM_INVAL;
        node_clear(node, nodes_found_map);
 }
+#endif  /*  0  */
 
 static void __init
 acpi_table_print_srat_entry(struct acpi_subtable_header *header)
@@ -247,7 +249,6 @@ int acpi_get_pxm(acpi_handle h)
        } while (ACPI_SUCCESS(status));
        return -1;
 }
-EXPORT_SYMBOL(acpi_get_pxm);
 
 int acpi_get_node(acpi_handle *handle)
 {
index e53fb516f9d45538dbfdedc002ad3dcb753e200e..27ccd68b8f462de790a7243219197e4631b8fcf9 100644 (file)
@@ -44,6 +44,8 @@
 #include <asm/uaccess.h>
 
 #include <linux/efi.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
 
 #define _COMPONENT             ACPI_OS_SERVICES
 ACPI_MODULE_NAME("osl");
@@ -74,9 +76,25 @@ static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
 static struct workqueue_struct *kacpi_notify_wq;
 
+struct acpi_res_list {
+       resource_size_t start;
+       resource_size_t end;
+       acpi_adr_space_type resource_type; /* IO port, System memory, ...*/
+       char name[5];   /* only can have a length of 4 chars, make use of this
+                          one instead of res->name, no need to kalloc then */
+       struct list_head resource_list;
+};
+
+static LIST_HEAD(resource_list_head);
+static DEFINE_SPINLOCK(acpi_res_lock);
+
 #define        OSI_STRING_LENGTH_MAX 64        /* arbitrary */
 static char osi_additional_string[OSI_STRING_LENGTH_MAX];
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+static int acpi_no_initrd_override;
+#endif
+
 /*
  * "Ode to _OSI(Linux)"
  *
@@ -120,7 +138,7 @@ static char osi_additional_string[OSI_STRING_LENGTH_MAX];
  */
 #define OSI_LINUX_ENABLE 0
 
-struct osi_linux {
+static struct osi_linux {
        unsigned int    enable:1;
        unsigned int    dmi:1;
        unsigned int    cmdline:1;
@@ -219,8 +237,6 @@ void acpi_os_printf(const char *fmt, ...)
        va_end(args);
 }
 
-EXPORT_SYMBOL(acpi_os_printf);
-
 void acpi_os_vprintf(const char *fmt, va_list args)
 {
        static char buffer[512];
@@ -250,11 +266,16 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
                               "System description tables not found\n");
                        return 0;
                }
-       } else
-               return acpi_find_rsdp();
+       } else {
+               acpi_physical_address pa = 0;
+
+               acpi_find_root_pointer(&pa);
+               return pa;
+       }
 }
 
-void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
+void __iomem *__init_refok
+acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
        if (phys > ULONG_MAX) {
                printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@ -312,6 +333,67 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
        return AE_OK;
 }
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+struct acpi_table_header *acpi_find_dsdt_initrd(void)
+{
+       struct file *firmware_file;
+       mm_segment_t oldfs;
+       unsigned long len, len2;
+       struct acpi_table_header *dsdt_buffer, *ret = NULL;
+       struct kstat stat;
+       char *ramfs_dsdt_name = "/DSDT.aml";
+
+       printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT");
+
+       /*
+        * Never do this at home, only the user-space is allowed to open a file.
+        * The clean way would be to use the firmware loader.
+        * But this code must be run before there is any userspace available.
+        * A static/init firmware infrastructure doesn't exist yet...
+        */
+       if (vfs_stat(ramfs_dsdt_name, &stat) < 0)
+               return ret;
+
+       len = stat.size;
+       /* check especially against empty files */
+       if (len <= 4) {
+               printk(KERN_ERR PREFIX "Failed: DSDT only %lu bytes.\n", len);
+               return ret;
+       }
+
+       firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0);
+       if (IS_ERR(firmware_file)) {
+               printk(KERN_ERR PREFIX "Failed to open %s.\n", ramfs_dsdt_name);
+               return ret;
+       }
+
+       dsdt_buffer = kmalloc(len, GFP_ATOMIC);
+       if (!dsdt_buffer) {
+               printk(KERN_ERR PREFIX "Failed to allocate %lu bytes.\n", len);
+               goto err;
+       }
+
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len,
+               &firmware_file->f_pos);
+       set_fs(oldfs);
+       if (len2 < len) {
+               printk(KERN_ERR PREFIX "Failed to read %lu bytes from %s.\n",
+                       len, ramfs_dsdt_name);
+               ACPI_FREE(dsdt_buffer);
+               goto err;
+       }
+
+       printk(KERN_INFO PREFIX "Found %lu byte DSDT in %s.\n",
+                       len, ramfs_dsdt_name);
+       ret = dsdt_buffer;
+err:
+       filp_close(firmware_file, NULL);
+       return ret;
+}
+#endif
+
 acpi_status
 acpi_os_table_override(struct acpi_table_header * existing_table,
                       struct acpi_table_header ** new_table)
@@ -319,20 +401,52 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
        if (!existing_table || !new_table)
                return AE_BAD_PARAMETER;
 
+       *new_table = NULL;
+
 #ifdef CONFIG_ACPI_CUSTOM_DSDT
        if (strncmp(existing_table->signature, "DSDT", 4) == 0)
                *new_table = (struct acpi_table_header *)AmlCode;
-       else
-               *new_table = NULL;
-#else
-       *new_table = NULL;
 #endif
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+       if ((strncmp(existing_table->signature, "DSDT", 4) == 0) &&
+           !acpi_no_initrd_override) {
+               struct acpi_table_header *initrd_table;
+
+               initrd_table = acpi_find_dsdt_initrd();
+               if (initrd_table)
+                       *new_table = initrd_table;
+       }
+#endif
+       if (*new_table != NULL) {
+               printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], "
+                          "this is unsafe: tainting kernel\n",
+                      existing_table->signature,
+                      existing_table->oem_table_id);
+               add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
+       }
        return AE_OK;
 }
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+int __init acpi_no_initrd_override_setup(char *s)
+{
+       acpi_no_initrd_override = 1;
+       return 1;
+}
+__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup);
+#endif
+
 static irqreturn_t acpi_irq(int irq, void *dev_id)
 {
-       return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
+       u32 handled;
+
+       handled = (*acpi_irq_handler) (acpi_irq_context);
+
+       if (handled) {
+               acpi_irq_handled++;
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
 }
 
 acpi_status
@@ -341,6 +455,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
 {
        unsigned int irq;
 
+       acpi_irq_stats_init();
+
        /*
         * Ignore the GSI from the core, and use the value in our copy of the
         * FADT. It may not be the same if an interrupt source override exists
@@ -384,8 +500,6 @@ void acpi_os_sleep(acpi_integer ms)
        schedule_timeout_interruptible(msecs_to_jiffies(ms));
 }
 
-EXPORT_SYMBOL(acpi_os_sleep);
-
 void acpi_os_stall(u32 us)
 {
        while (us) {
@@ -399,8 +513,6 @@ void acpi_os_stall(u32 us)
        }
 }
 
-EXPORT_SYMBOL(acpi_os_stall);
-
 /*
  * Support ACPI 3.0 AML Timer operand
  * Returns 64-bit free-running, monotonically increasing timer
@@ -550,8 +662,6 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
        return (result ? AE_ERROR : AE_OK);
 }
 
-EXPORT_SYMBOL(acpi_os_read_pci_configuration);
-
 acpi_status
 acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
                                acpi_integer value, u32 width)
@@ -661,25 +771,6 @@ static void acpi_os_execute_deferred(struct work_struct *work)
        dpc->function(dpc->context);
        kfree(dpc);
 
-       /* Yield cpu to notify thread */
-       cond_resched();
-
-       return;
-}
-
-static void acpi_os_execute_notify(struct work_struct *work)
-{
-       struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
-
-       if (!dpc) {
-               printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
-               return;
-       }
-
-       dpc->function(dpc->context);
-
-       kfree(dpc);
-
        return;
 }
 
@@ -703,7 +794,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 {
        acpi_status status = AE_OK;
        struct acpi_os_dpc *dpc;
-
+       struct workqueue_struct *queue;
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
                          "Scheduling function [%p(%p)] for deferred execution.\n",
                          function, context));
@@ -727,20 +818,13 @@ acpi_status acpi_os_execute(acpi_execute_type type,
        dpc->function = function;
        dpc->context = context;
 
-       if (type == OSL_NOTIFY_HANDLER) {
-               INIT_WORK(&dpc->work, acpi_os_execute_notify);
-               if (!queue_work(kacpi_notify_wq, &dpc->work)) {
-                       status = AE_ERROR;
-                       kfree(dpc);
-               }
-       } else {
-               INIT_WORK(&dpc->work, acpi_os_execute_deferred);
-               if (!queue_work(kacpid_wq, &dpc->work)) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "Call to queue_work() failed.\n"));
-                       status = AE_ERROR;
-                       kfree(dpc);
-               }
+       INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+       queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
+       if (!queue_work(queue, &dpc->work)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                         "Call to queue_work() failed.\n"));
+               status = AE_ERROR;
+               kfree(dpc);
        }
        return_ACPI_STATUS(status);
 }
@@ -793,8 +877,6 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
        return AE_OK;
 }
 
-EXPORT_SYMBOL(acpi_os_create_semaphore);
-
 /*
  * TODO: A better way to delete semaphores?  Linux doesn't have a
  * 'delete_semaphore()' function -- may result in an invalid
@@ -818,8 +900,6 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle)
        return AE_OK;
 }
 
-EXPORT_SYMBOL(acpi_os_delete_semaphore);
-
 /*
  * TODO: The kernel doesn't have a 'down_timeout' function -- had to
  * improvise.  The process is to sleep for one scheduler quantum
@@ -912,8 +992,6 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
        return status;
 }
 
-EXPORT_SYMBOL(acpi_os_wait_semaphore);
-
 /*
  * TODO: Support for units > 1?
  */
@@ -936,8 +1014,6 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
        return AE_OK;
 }
 
-EXPORT_SYMBOL(acpi_os_signal_semaphore);
-
 #ifdef ACPI_FUTURE_USAGE
 u32 acpi_os_get_line(char *buffer)
 {
@@ -981,8 +1057,6 @@ acpi_status acpi_os_signal(u32 function, void *info)
        return AE_OK;
 }
 
-EXPORT_SYMBOL(acpi_os_signal);
-
 static int __init acpi_os_name_setup(char *str)
 {
        char *p = acpi_os_name;
@@ -1102,6 +1176,128 @@ static int __init acpi_wake_gpes_always_on_setup(char *str)
 
 __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
 
+/* Check of resource interference between native drivers and ACPI
+ * OperationRegions (SystemIO and System Memory only).
+ * IO ports and memory declared in ACPI might be used by the ACPI subsystem
+ * in arbitrary AML code and can interfere with legacy drivers.
+ * acpi_enforce_resources= can be set to:
+ *
+ *   - strict           (2)
+ *     -> further driver trying to access the resources will not load
+ *   - lax (default)    (1)
+ *     -> further driver trying to access the resources will load, but you
+ *     get a system message that something might go wrong...
+ *
+ *   - no               (0)
+ *     -> ACPI Operation Region resources will not be registered
+ *
+ */
+#define ENFORCE_RESOURCES_STRICT 2
+#define ENFORCE_RESOURCES_LAX    1
+#define ENFORCE_RESOURCES_NO     0
+
+static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
+
+static int __init acpi_enforce_resources_setup(char *str)
+{
+       if (str == NULL || *str == '\0')
+               return 0;
+
+       if (!strcmp("strict", str))
+               acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
+       else if (!strcmp("lax", str))
+               acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
+       else if (!strcmp("no", str))
+               acpi_enforce_resources = ENFORCE_RESOURCES_NO;
+
+       return 1;
+}
+
+__setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
+
+/* Check for resource conflicts between ACPI OperationRegions and native
+ * drivers */
+int acpi_check_resource_conflict(struct resource *res)
+{
+       struct acpi_res_list *res_list_elem;
+       int ioport;
+       int clash = 0;
+
+       if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
+               return 0;
+       if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))
+               return 0;
+
+       ioport = res->flags & IORESOURCE_IO;
+
+       spin_lock(&acpi_res_lock);
+       list_for_each_entry(res_list_elem, &resource_list_head,
+                           resource_list) {
+               if (ioport && (res_list_elem->resource_type
+                              != ACPI_ADR_SPACE_SYSTEM_IO))
+                       continue;
+               if (!ioport && (res_list_elem->resource_type
+                               != ACPI_ADR_SPACE_SYSTEM_MEMORY))
+                       continue;
+
+               if (res->end < res_list_elem->start
+                   || res_list_elem->end < res->start)
+                       continue;
+               clash = 1;
+               break;
+       }
+       spin_unlock(&acpi_res_lock);
+
+       if (clash) {
+               if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
+                       printk(KERN_INFO "%sACPI: %s resource %s [0x%llx-0x%llx]"
+                              " conflicts with ACPI region %s"
+                              " [0x%llx-0x%llx]\n",
+                              acpi_enforce_resources == ENFORCE_RESOURCES_LAX
+                              ? KERN_WARNING : KERN_ERR,
+                              ioport ? "I/O" : "Memory", res->name,
+                              (long long) res->start, (long long) res->end,
+                              res_list_elem->name,
+                              (long long) res_list_elem->start,
+                              (long long) res_list_elem->end);
+                       printk(KERN_INFO "ACPI: Device needs an ACPI driver\n");
+               }
+               if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
+                       return -EBUSY;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(acpi_check_resource_conflict);
+
+int acpi_check_region(resource_size_t start, resource_size_t n,
+                     const char *name)
+{
+       struct resource res = {
+               .start = start,
+               .end   = start + n - 1,
+               .name  = name,
+               .flags = IORESOURCE_IO,
+       };
+
+       return acpi_check_resource_conflict(&res);
+}
+EXPORT_SYMBOL(acpi_check_region);
+
+int acpi_check_mem_region(resource_size_t start, resource_size_t n,
+                     const char *name)
+{
+       struct resource res = {
+               .start = start,
+               .end   = start + n - 1,
+               .name  = name,
+               .flags = IORESOURCE_MEM,
+       };
+
+       return acpi_check_resource_conflict(&res);
+
+}
+EXPORT_SYMBOL(acpi_check_mem_region);
+
 /*
  * Acquire a spinlock.
  *
@@ -1213,24 +1409,24 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
  *
  *     Returns 0 on success
  */
-int acpi_dmi_dump(void)
+static int acpi_dmi_dump(void)
 {
 
        if (!dmi_available)
                return -1;
 
        printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
-               dmi_get_slot(DMI_SYS_VENDOR));
+               dmi_get_system_info(DMI_SYS_VENDOR));
        printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
-               dmi_get_slot(DMI_PRODUCT_NAME));
+               dmi_get_system_info(DMI_PRODUCT_NAME));
        printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
-               dmi_get_slot(DMI_PRODUCT_VERSION));
+               dmi_get_system_info(DMI_PRODUCT_VERSION));
        printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
-               dmi_get_slot(DMI_BOARD_NAME));
+               dmi_get_system_info(DMI_BOARD_NAME));
        printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
-               dmi_get_slot(DMI_BIOS_VENDOR));
+               dmi_get_system_info(DMI_BIOS_VENDOR));
        printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
-               dmi_get_slot(DMI_BIOS_DATE));
+               dmi_get_system_info(DMI_BIOS_DATE));
 
        return 0;
 }
@@ -1303,10 +1499,46 @@ acpi_status
 acpi_os_validate_address (
     u8                   space_id,
     acpi_physical_address   address,
-    acpi_size               length)
+    acpi_size               length,
+    char *name)
 {
+       struct acpi_res_list *res;
+       if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
+               return AE_OK;
 
-    return AE_OK;
+       switch (space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               /* Only interference checks against SystemIO and SytemMemory
+                  are needed */
+               res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL);
+               if (!res)
+                       return AE_OK;
+               /* ACPI names are fixed to 4 bytes, still better use strlcpy */
+               strlcpy(res->name, name, 5);
+               res->start = address;
+               res->end = address + length - 1;
+               res->resource_type = space_id;
+               spin_lock(&acpi_res_lock);
+               list_add(&res->resource_list, &resource_list_head);
+               spin_unlock(&acpi_res_lock);
+               pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, "
+                        "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+                        ? "SystemIO" : "System Memory",
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end,
+                        res->name);
+               break;
+       case ACPI_ADR_SPACE_PCI_CONFIG:
+       case ACPI_ADR_SPACE_EC:
+       case ACPI_ADR_SPACE_SMBUS:
+       case ACPI_ADR_SPACE_CMOS:
+       case ACPI_ADR_SPACE_PCI_BAR_TARGET:
+       case ACPI_ADR_SPACE_DATA_TABLE:
+       case ACPI_ADR_SPACE_FIXED_HARDWARE:
+               break;
+       }
+       return AE_OK;
 }
 
 #endif
index 388300de005d37df692f142649e0e1a1ab75d9c0..4b252ea0e95268838529eb1a126f532525651559 100644 (file)
@@ -44,6 +44,8 @@ struct acpi_pci_data {
        struct pci_dev *dev;
 };
 
+static int acpi_pci_unbind(struct acpi_device *device);
+
 static void acpi_pci_data_handler(acpi_handle handle, u32 function,
                                  void *context)
 {
@@ -267,7 +269,7 @@ int acpi_pci_bind(struct acpi_device *device)
        return result;
 }
 
-int acpi_pci_unbind(struct acpi_device *device)
+static int acpi_pci_unbind(struct acpi_device *device)
 {
        int result = 0;
        acpi_status status = AE_OK;
index 62010c2481b3614b9b9ddd3e1cbbae2118f40fd7..7f19859580c7efcbdf9675d6be44436573d0e8d6 100644 (file)
@@ -51,10 +51,8 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
                                                          int bus,
                                                          int device, int pin)
 {
-       struct list_head *node = NULL;
        struct acpi_prt_entry *entry = NULL;
 
-
        if (!acpi_prt.count)
                return NULL;
 
@@ -64,8 +62,7 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
         *
         */
        spin_lock(&acpi_prt_lock);
-       list_for_each(node, &acpi_prt.entries) {
-               entry = list_entry(node, struct acpi_prt_entry, node);
+       list_for_each_entry(entry, &acpi_prt.entries, node) {
                if ((segment == entry->id.segment)
                    && (bus == entry->id.bus)
                    && (device == entry->id.device)
@@ -478,8 +475,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
        return 0;
 }
 
-EXPORT_SYMBOL(acpi_pci_irq_enable);
-
 /* FIXME: implement x86/x86_64 version */
 void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)
 {
index 5400ea173f6fdf0fe309658e2c4de0b13bdbd462..233c40c5168412da11e3bd826a7d3a3fadd0691d 100644 (file)
@@ -95,7 +95,7 @@ static struct {
        int count;
        struct list_head entries;
 } acpi_link;
-DEFINE_MUTEX(acpi_link_lock);
+static DEFINE_MUTEX(acpi_link_lock);
 
 /* --------------------------------------------------------------------------
                             PCI Link Device Management
index af1769a20c7a6ba3f0ee665b204a79c0a1f0c74c..76bf6d90c700efac7905d6167680915ca50e1498 100644 (file)
@@ -458,11 +458,9 @@ int acpi_power_transition(struct acpi_device *device, int state)
        }
 
      end:
-       if (result) {
+       if (result)
                device->power.state = ACPI_STATE_UNKNOWN;
-               printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n",
-                             device->pnp.bus_id, state);
-       } else {
+       else {
        /* We shouldn't change the state till all above operations succeed */
                device->power.state = state;
        }
index e48ee4f8749f4afea2e2ec72aff27e05eb30a552..75ccf5d18bf4e3630e892dd0021a8c890a0fc0c2 100644 (file)
@@ -668,6 +668,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
 
        acpi_processor_power_init(pr, device);
 
+       pr->cdev = thermal_cooling_device_register("Processor", device,
+                                               &processor_cooling_ops);
+       if (pr->cdev)
+               printk(KERN_INFO PREFIX
+                       "%s is registered as cooling_device%d\n",
+                       device->dev.bus_id, pr->cdev->id);
+       else
+               goto end;
+
+       result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj,
+                                       "thermal_cooling");
+       if (result)
+               return result;
+       result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj,
+                                       "device");
+       if (result)
+               return result;
+
        if (pr->flags.throttling) {
                printk(KERN_INFO PREFIX "%s [%s] (supports",
                       acpi_device_name(device), acpi_device_bid(device));
@@ -791,6 +809,11 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
 
        acpi_processor_remove_fs(device);
 
+       sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+       sysfs_remove_link(&pr->cdev->device.kobj, "device");
+       thermal_cooling_device_unregister(pr->cdev);
+       pr->cdev = NULL;
+
        processors[pr->id] = NULL;
 
        kfree(pr);
@@ -812,11 +835,18 @@ static int is_processor_present(acpi_handle handle)
 
 
        status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-       if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
-               return 0;
-       }
-       return 1;
+       /*
+        * if a processor object does not have an _STA object,
+        * OSPM assumes that the processor is present.
+        */
+       if (status == AE_NOT_FOUND)
+               return 1;
+
+       if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
+               return 1;
+
+       ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
+       return 0;
 }
 
 static
@@ -1061,6 +1091,8 @@ static int __init acpi_processor_init(void)
 
        acpi_processor_ppc_init();
 
+       acpi_processor_throttling_init();
+
        return 0;
 
 out_cpuidle:
index 199ea21461534cf835cefdafd641b5194bc8a1d1..32003fdc91e8a4b0205f3fbf2bedfbfc91260399 100644 (file)
@@ -98,6 +98,9 @@ module_param(bm_history, uint, 0644);
 
 static int acpi_processor_set_power_policy(struct acpi_processor *pr);
 
+#else  /* CONFIG_CPU_IDLE */
+static unsigned int latency_factor __read_mostly = 2;
+module_param(latency_factor, uint, 0644);
 #endif
 
 /*
@@ -201,6 +204,10 @@ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
                return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
 }
 
+/*
+ * Callers should disable interrupts before the call and enable
+ * interrupts after return.
+ */
 static void acpi_safe_halt(void)
 {
        current_thread_info()->status &= ~TS_POLLING;
@@ -261,7 +268,7 @@ static atomic_t c3_cpu_count;
 /* Common C-state entry for C2, C3, .. */
 static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
 {
-       if (cstate->space_id == ACPI_CSTATE_FFH) {
+       if (cstate->entry_method == ACPI_CSTATE_FFH) {
                /* Call into architectural FFH based C-state */
                acpi_processor_ffh_cstate_enter(cstate);
        } else {
@@ -413,6 +420,8 @@ static void acpi_processor_idle(void)
                        pm_idle_save();
                else
                        acpi_safe_halt();
+
+               local_irq_enable();
                return;
        }
 
@@ -521,6 +530,7 @@ static void acpi_processor_idle(void)
                 *       skew otherwise.
                 */
                sleep_ticks = 0xFFFFFFFF;
+               local_irq_enable();
                break;
 
        case ACPI_STATE_C2:
@@ -922,20 +932,20 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
                cx.address = reg->address;
                cx.index = current_count + 1;
 
-               cx.space_id = ACPI_CSTATE_SYSTEMIO;
+               cx.entry_method = ACPI_CSTATE_SYSTEMIO;
                if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
                        if (acpi_processor_ffh_cstate_probe
                                        (pr->id, &cx, reg) == 0) {
-                               cx.space_id = ACPI_CSTATE_FFH;
-                       } else if (cx.type != ACPI_STATE_C1) {
+                               cx.entry_method = ACPI_CSTATE_FFH;
+                       } else if (cx.type == ACPI_STATE_C1) {
                                /*
                                 * C1 is a special case where FIXED_HARDWARE
                                 * can be handled in non-MWAIT way as well.
                                 * In that case, save this _CST entry info.
-                                * That is, we retain space_id of SYSTEM_IO for
-                                * halt based C1.
                                 * Otherwise, ignore this info and continue.
                                 */
+                               cx.entry_method = ACPI_CSTATE_HALT;
+                       } else {
                                continue;
                        }
                }
@@ -1369,12 +1379,16 @@ static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr,
 /**
  * acpi_idle_do_entry - a helper function that does C2 and C3 type entry
  * @cx: cstate data
+ *
+ * Caller disables interrupt before call and enables interrupt after return.
  */
 static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
 {
-       if (cx->space_id == ACPI_CSTATE_FFH) {
+       if (cx->entry_method == ACPI_CSTATE_FFH) {
                /* Call into architectural FFH based C-state */
                acpi_processor_ffh_cstate_enter(cx);
+       } else if (cx->entry_method == ACPI_CSTATE_HALT) {
+               acpi_safe_halt();
        } else {
                int unused;
                /* IO port based C-state */
@@ -1396,21 +1410,27 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
 static int acpi_idle_enter_c1(struct cpuidle_device *dev,
                              struct cpuidle_state *state)
 {
+       u32 t1, t2;
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+
        pr = processors[smp_processor_id()];
 
        if (unlikely(!pr))
                return 0;
 
+       local_irq_disable();
        if (pr->flags.bm_check)
                acpi_idle_update_bm_rld(pr, cx);
 
-       acpi_safe_halt();
+       t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       acpi_idle_do_entry(cx);
+       t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
+       local_irq_enable();
        cx->usage++;
 
-       return 0;
+       return ticks_elapsed_in_us(t1, t2);
 }
 
 /**
@@ -1517,7 +1537,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                if (dev->safe_state) {
                        return dev->safe_state->enter(dev, dev->safe_state);
                } else {
+                       local_irq_disable();
                        acpi_safe_halt();
+                       local_irq_enable();
                        return 0;
                }
        }
@@ -1609,7 +1631,7 @@ struct cpuidle_driver acpi_idle_driver = {
  */
 static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 {
-       int i, count = 0;
+       int i, count = CPUIDLE_DRIVER_STATE_START;
        struct acpi_processor_cx *cx;
        struct cpuidle_state *state;
        struct cpuidle_device *dev = &pr->power.dev;
@@ -1638,13 +1660,14 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 
                snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
                state->exit_latency = cx->latency;
-               state->target_residency = cx->latency * 6;
+               state->target_residency = cx->latency * latency_factor;
                state->power_usage = cx->power;
 
                state->flags = 0;
                switch (cx->type) {
                        case ACPI_STATE_C1:
                        state->flags |= CPUIDLE_FLAG_SHALLOW;
+                       state->flags |= CPUIDLE_FLAG_TIME_VALID;
                        state->enter = acpi_idle_enter_c1;
                        dev->safe_state = state;
                        break;
@@ -1667,6 +1690,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
                }
 
                count++;
+               if (count == CPUIDLE_STATE_MAX)
+                       break;
        }
 
        dev->state_count = count;
index 463b0247cbc517c40567446df9446fff389c849b..f32010bee4d5650a6896624bab290a4d560e916c 100644 (file)
@@ -60,6 +60,11 @@ static DEFINE_MUTEX(performance_mutex);
  * policy is adjusted accordingly.
  */
 
+static unsigned int ignore_ppc = 0;
+module_param(ignore_ppc, uint, 0644);
+MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
+                "limited by BIOS, this should help");
+
 #define PPC_REGISTERED   1
 #define PPC_IN_USE       2
 
@@ -72,6 +77,9 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
        struct acpi_processor *pr;
        unsigned int ppc = 0;
 
+       if (ignore_ppc)
+               return 0;
+
        mutex_lock(&performance_mutex);
 
        if (event != CPUFREQ_INCOMPATIBLE)
@@ -130,7 +138,13 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
 
 int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
 {
-       int ret = acpi_processor_get_platform_limit(pr);
+       int ret;
+
+       if (ignore_ppc)
+               return 0;
+
+       ret = acpi_processor_get_platform_limit(pr);
+
        if (ret < 0)
                return (ret);
        else
index 06e6f3fb88254d61dda243f390a7eabc509696aa..9cb43f52f7b6cf45bed03ab7ef0c74eab93e7a7f 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/cpufreq.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/sysdev.h>
 
 #include <asm/uaccess.h>
 
@@ -93,6 +94,9 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr)
  * _any_ cpufreq driver and not only the acpi-cpufreq driver.
  */
 
+#define CPUFREQ_THERMAL_MIN_STEP 0
+#define CPUFREQ_THERMAL_MAX_STEP 3
+
 static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];
 static unsigned int acpi_thermal_cpufreq_is_init = 0;
 
@@ -109,8 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu)
        if (!cpu_has_cpufreq(cpu))
                return -ENODEV;
 
-       if (cpufreq_thermal_reduction_pctg[cpu] < 60) {
-               cpufreq_thermal_reduction_pctg[cpu] += 20;
+       if (cpufreq_thermal_reduction_pctg[cpu] <
+               CPUFREQ_THERMAL_MAX_STEP) {
+               cpufreq_thermal_reduction_pctg[cpu]++;
                cpufreq_update_policy(cpu);
                return 0;
        }
@@ -123,8 +128,9 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
        if (!cpu_has_cpufreq(cpu))
                return -ENODEV;
 
-       if (cpufreq_thermal_reduction_pctg[cpu] > 20)
-               cpufreq_thermal_reduction_pctg[cpu] -= 20;
+       if (cpufreq_thermal_reduction_pctg[cpu] >
+               (CPUFREQ_THERMAL_MIN_STEP + 1))
+               cpufreq_thermal_reduction_pctg[cpu]--;
        else
                cpufreq_thermal_reduction_pctg[cpu] = 0;
        cpufreq_update_policy(cpu);
@@ -143,7 +149,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
 
        max_freq =
            (policy->cpuinfo.max_freq *
-            (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100;
+            (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100;
 
        cpufreq_verify_within_limits(policy, 0, max_freq);
 
@@ -155,6 +161,32 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
        .notifier_call = acpi_thermal_cpufreq_notifier,
 };
 
+static int cpufreq_get_max_state(unsigned int cpu)
+{
+       if (!cpu_has_cpufreq(cpu))
+               return 0;
+
+       return CPUFREQ_THERMAL_MAX_STEP;
+}
+
+static int cpufreq_get_cur_state(unsigned int cpu)
+{
+       if (!cpu_has_cpufreq(cpu))
+               return 0;
+
+       return cpufreq_thermal_reduction_pctg[cpu];
+}
+
+static int cpufreq_set_cur_state(unsigned int cpu, int state)
+{
+       if (!cpu_has_cpufreq(cpu))
+               return 0;
+
+       cpufreq_thermal_reduction_pctg[cpu] = state;
+       cpufreq_update_policy(cpu);
+       return 0;
+}
+
 void acpi_thermal_cpufreq_init(void)
 {
        int i;
@@ -179,6 +211,20 @@ void acpi_thermal_cpufreq_exit(void)
 }
 
 #else                          /* ! CONFIG_CPU_FREQ */
+static int cpufreq_get_max_state(unsigned int cpu)
+{
+       return 0;
+}
+
+static int cpufreq_get_cur_state(unsigned int cpu)
+{
+       return 0;
+}
+
+static int cpufreq_set_cur_state(unsigned int cpu, int state)
+{
+       return 0;
+}
 
 static int acpi_thermal_cpufreq_increase(unsigned int cpu)
 {
@@ -310,6 +356,84 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr)
        return 0;
 }
 
+/* thermal coolign device callbacks */
+static int acpi_processor_max_state(struct acpi_processor *pr)
+{
+       int max_state = 0;
+
+       /*
+        * There exists four states according to
+        * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3
+        */
+       max_state += cpufreq_get_max_state(pr->id);
+       if (pr->flags.throttling)
+               max_state += (pr->throttling.state_count -1);
+
+       return max_state;
+}
+static int
+processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+{
+       struct acpi_device *device = cdev->devdata;
+       struct acpi_processor *pr = acpi_driver_data(device);
+
+       if (!device || !pr)
+               return -EINVAL;
+
+       return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
+}
+
+static int
+processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+{
+       struct acpi_device *device = cdev->devdata;
+       struct acpi_processor *pr = acpi_driver_data(device);
+       int cur_state;
+
+       if (!device || !pr)
+               return -EINVAL;
+
+       cur_state = cpufreq_get_cur_state(pr->id);
+       if (pr->flags.throttling)
+               cur_state += pr->throttling.state;
+
+       return sprintf(buf, "%d\n", cur_state);
+}
+
+static int
+processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+{
+       struct acpi_device *device = cdev->devdata;
+       struct acpi_processor *pr = acpi_driver_data(device);
+       int result = 0;
+       int max_pstate;
+
+       if (!device || !pr)
+               return -EINVAL;
+
+       max_pstate = cpufreq_get_max_state(pr->id);
+
+       if (state > acpi_processor_max_state(pr))
+               return -EINVAL;
+
+       if (state <= max_pstate) {
+               if (pr->flags.throttling && pr->throttling.state)
+                       result = acpi_processor_set_throttling(pr, 0);
+               cpufreq_set_cur_state(pr->id, state);
+       } else {
+               cpufreq_set_cur_state(pr->id, max_pstate);
+               result = acpi_processor_set_throttling(pr,
+                               state - max_pstate);
+       }
+       return result;
+}
+
+struct thermal_cooling_device_ops processor_cooling_ops = {
+       .get_max_state = processor_get_max_state,
+       .get_cur_state = processor_get_cur_state,
+       .set_cur_state = processor_set_cur_state,
+};
+
 /* /proc interface */
 
 static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
index 1685b40abda7c2dba944939917a4993f8a4a5f3d..1b8e592a82415a0772ebf1474acde406229236c9 100644 (file)
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_throttling");
 
+struct throttling_tstate {
+       unsigned int cpu;               /* cpu nr */
+       int target_state;               /* target T-state */
+};
+
+#define THROTTLING_PRECHANGE       (1)
+#define THROTTLING_POSTCHANGE      (2)
+
 static int acpi_processor_get_throttling(struct acpi_processor *pr);
 int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
 
+static int acpi_processor_update_tsd_coord(void)
+{
+       int count, count_target;
+       int retval = 0;
+       unsigned int i, j;
+       cpumask_t covered_cpus;
+       struct acpi_processor *pr, *match_pr;
+       struct acpi_tsd_package *pdomain, *match_pdomain;
+       struct acpi_processor_throttling *pthrottling, *match_pthrottling;
+
+       /*
+        * Now that we have _TSD data from all CPUs, lets setup T-state
+        * coordination between all CPUs.
+        */
+       for_each_possible_cpu(i) {
+               pr = processors[i];
+               if (!pr)
+                       continue;
+
+               /* Basic validity check for domain info */
+               pthrottling = &(pr->throttling);
+
+               /*
+                * If tsd package for one cpu is invalid, the coordination
+                * among all CPUs is thought as invalid.
+                * Maybe it is ugly.
+                */
+               if (!pthrottling->tsd_valid_flag) {
+                       retval = -EINVAL;
+                       break;
+               }
+       }
+       if (retval)
+               goto err_ret;
+
+       cpus_clear(covered_cpus);
+       for_each_possible_cpu(i) {
+               pr = processors[i];
+               if (!pr)
+                       continue;
+
+               if (cpu_isset(i, covered_cpus))
+                       continue;
+               pthrottling = &pr->throttling;
+
+               pdomain = &(pthrottling->domain_info);
+               cpu_set(i, pthrottling->shared_cpu_map);
+               cpu_set(i, covered_cpus);
+               /*
+                * If the number of processor in the TSD domain is 1, it is
+                * unnecessary to parse the coordination for this CPU.
+                */
+               if (pdomain->num_processors <= 1)
+                       continue;
+
+               /* Validate the Domain info */
+               count_target = pdomain->num_processors;
+               count = 1;
+
+               for_each_possible_cpu(j) {
+                       if (i == j)
+                               continue;
+
+                       match_pr = processors[j];
+                       if (!match_pr)
+                               continue;
+
+                       match_pthrottling = &(match_pr->throttling);
+                       match_pdomain = &(match_pthrottling->domain_info);
+                       if (match_pdomain->domain != pdomain->domain)
+                               continue;
+
+                       /* Here i and j are in the same domain.
+                        * If two TSD packages have the same domain, they
+                        * should have the same num_porcessors and
+                        * coordination type. Otherwise it will be regarded
+                        * as illegal.
+                        */
+                       if (match_pdomain->num_processors != count_target) {
+                               retval = -EINVAL;
+                               goto err_ret;
+                       }
+
+                       if (pdomain->coord_type != match_pdomain->coord_type) {
+                               retval = -EINVAL;
+                               goto err_ret;
+                       }
+
+                       cpu_set(j, covered_cpus);
+                       cpu_set(j, pthrottling->shared_cpu_map);
+                       count++;
+               }
+               for_each_possible_cpu(j) {
+                       if (i == j)
+                               continue;
+
+                       match_pr = processors[j];
+                       if (!match_pr)
+                               continue;
+
+                       match_pthrottling = &(match_pr->throttling);
+                       match_pdomain = &(match_pthrottling->domain_info);
+                       if (match_pdomain->domain != pdomain->domain)
+                               continue;
+
+                       /*
+                        * If some CPUS have the same domain, they
+                        * will have the same shared_cpu_map.
+                        */
+                       match_pthrottling->shared_cpu_map =
+                               pthrottling->shared_cpu_map;
+               }
+       }
+
+err_ret:
+       for_each_possible_cpu(i) {
+               pr = processors[i];
+               if (!pr)
+                       continue;
+
+               /*
+                * Assume no coordination on any error parsing domain info.
+                * The coordination type will be forced as SW_ALL.
+                */
+               if (retval) {
+                       pthrottling = &(pr->throttling);
+                       cpus_clear(pthrottling->shared_cpu_map);
+                       cpu_set(i, pthrottling->shared_cpu_map);
+                       pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
+               }
+       }
+
+       return retval;
+}
+
+/*
+ * Update the T-state coordination after the _TSD
+ * data for all cpus is obtained.
+ */
+void acpi_processor_throttling_init(void)
+{
+       if (acpi_processor_update_tsd_coord())
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                       "Assume no T-state coordination\n"));
+
+       return;
+}
+
+static int acpi_processor_throttling_notifier(unsigned long event, void *data)
+{
+       struct throttling_tstate *p_tstate = data;
+       struct acpi_processor *pr;
+       unsigned int cpu ;
+       int target_state;
+       struct acpi_processor_limit *p_limit;
+       struct acpi_processor_throttling *p_throttling;
+
+       cpu = p_tstate->cpu;
+       pr = processors[cpu];
+       if (!pr) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid pr pointer\n"));
+               return 0;
+       }
+       if (!pr->flags.throttling) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling control is "
+                               "unsupported on CPU %d\n", cpu));
+               return 0;
+       }
+       target_state = p_tstate->target_state;
+       p_throttling = &(pr->throttling);
+       switch (event) {
+       case THROTTLING_PRECHANGE:
+               /*
+                * Prechange event is used to choose one proper t-state,
+                * which meets the limits of thermal, user and _TPC.
+                */
+               p_limit = &pr->limit;
+               if (p_limit->thermal.tx > target_state)
+                       target_state = p_limit->thermal.tx;
+               if (p_limit->user.tx > target_state)
+                       target_state = p_limit->user.tx;
+               if (pr->throttling_platform_limit > target_state)
+                       target_state = pr->throttling_platform_limit;
+               if (target_state >= p_throttling->state_count) {
+                       printk(KERN_WARNING
+                               "Exceed the limit of T-state \n");
+                       target_state = p_throttling->state_count - 1;
+               }
+               p_tstate->target_state = target_state;
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PreChange Event:"
+                               "target T-state of CPU %d is T%d\n",
+                               cpu, target_state));
+               break;
+       case THROTTLING_POSTCHANGE:
+               /*
+                * Postchange event is only used to update the
+                * T-state flag of acpi_processor_throttling.
+                */
+               p_throttling->state = target_state;
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PostChange Event:"
+                               "CPU %d is switched to T%d\n",
+                               cpu, target_state));
+               break;
+       default:
+               printk(KERN_WARNING
+                       "Unsupported Throttling notifier event\n");
+               break;
+       }
+
+       return 0;
+}
+
 /*
  * _TPC - Throttling Present Capabilities
  */
@@ -293,6 +513,10 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
        struct acpi_buffer state = { 0, NULL };
        union acpi_object *tsd = NULL;
        struct acpi_tsd_package *pdomain;
+       struct acpi_processor_throttling *pthrottling;
+
+       pthrottling = &pr->throttling;
+       pthrottling->tsd_valid_flag = 0;
 
        status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
        if (ACPI_FAILURE(status)) {
@@ -340,6 +564,22 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
                goto end;
        }
 
+       pthrottling = &pr->throttling;
+       pthrottling->tsd_valid_flag = 1;
+       pthrottling->shared_type = pdomain->coord_type;
+       cpu_set(pr->id, pthrottling->shared_cpu_map);
+       /*
+        * If the coordination type is not defined in ACPI spec,
+        * the tsd_valid_flag will be clear and coordination type
+        * will be forecd as DOMAIN_COORD_TYPE_SW_ALL.
+        */
+       if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
+               pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
+               pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
+               pthrottling->tsd_valid_flag = 0;
+               pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
+       }
+
       end:
        kfree(buffer.pointer);
        return result;
@@ -589,6 +829,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
        cpumask_t saved_mask;
        int ret;
 
+       if (!pr)
+               return -EINVAL;
+
+       if (!pr->flags.throttling)
+               return -ENODEV;
        /*
         * Migrate task to the cpu pointed by pr.
         */
@@ -742,13 +987,92 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
 int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
 {
        cpumask_t saved_mask;
-       int ret;
+       int ret = 0;
+       unsigned int i;
+       struct acpi_processor *match_pr;
+       struct acpi_processor_throttling *p_throttling;
+       struct throttling_tstate t_state;
+       cpumask_t online_throttling_cpus;
+
+       if (!pr)
+               return -EINVAL;
+
+       if (!pr->flags.throttling)
+               return -ENODEV;
+
+       if ((state < 0) || (state > (pr->throttling.state_count - 1)))
+               return -EINVAL;
+
+       saved_mask = current->cpus_allowed;
+       t_state.target_state = state;
+       p_throttling = &(pr->throttling);
+       cpus_and(online_throttling_cpus, cpu_online_map,
+                       p_throttling->shared_cpu_map);
        /*
-        * Migrate task to the cpu pointed by pr.
+        * The throttling notifier will be called for every
+        * affected cpu in order to get one proper T-state.
+        * The notifier event is THROTTLING_PRECHANGE.
         */
-       saved_mask = current->cpus_allowed;
-       set_cpus_allowed(current, cpumask_of_cpu(pr->id));
-       ret = pr->throttling.acpi_processor_set_throttling(pr, state);
+       for_each_cpu_mask(i, online_throttling_cpus) {
+               t_state.cpu = i;
+               acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
+                                                       &t_state);
+       }
+       /*
+        * The function of acpi_processor_set_throttling will be called
+        * to switch T-state. If the coordination type is SW_ALL or HW_ALL,
+        * it is necessary to call it for every affected cpu. Otherwise
+        * it can be called only for the cpu pointed by pr.
+        */
+       if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
+               set_cpus_allowed(current, cpumask_of_cpu(pr->id));
+               ret = p_throttling->acpi_processor_set_throttling(pr,
+                                               t_state.target_state);
+       } else {
+               /*
+                * When the T-state coordination is SW_ALL or HW_ALL,
+                * it is necessary to set T-state for every affected
+                * cpus.
+                */
+               for_each_cpu_mask(i, online_throttling_cpus) {
+                       match_pr = processors[i];
+                       /*
+                        * If the pointer is invalid, we will report the
+                        * error message and continue.
+                        */
+                       if (!match_pr) {
+                               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                       "Invalid Pointer for CPU %d\n", i));
+                               continue;
+                       }
+                       /*
+                        * If the throttling control is unsupported on CPU i,
+                        * we will report the error message and continue.
+                        */
+                       if (!match_pr->flags.throttling) {
+                               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                       "Throttling Controll is unsupported "
+                                       "on CPU %d\n", i));
+                               continue;
+                       }
+                       t_state.cpu = i;
+                       set_cpus_allowed(current, cpumask_of_cpu(i));
+                       ret = match_pr->throttling.
+                               acpi_processor_set_throttling(
+                               match_pr, t_state.target_state);
+               }
+       }
+       /*
+        * After the set_throttling is called, the
+        * throttling notifier is called for every
+        * affected cpu to update the T-states.
+        * The notifier event is THROTTLING_POSTCHANGE
+        */
+       for_each_cpu_mask(i, online_throttling_cpus) {
+               t_state.cpu = i;
+               acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
+                                                       &t_state);
+       }
        /* restore the previous state */
        set_cpus_allowed(current, saved_mask);
        return ret;
@@ -757,6 +1081,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
 int acpi_processor_get_throttling_info(struct acpi_processor *pr)
 {
        int result = 0;
+       struct acpi_processor_throttling *pthrottling;
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
@@ -788,7 +1113,16 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
                    &acpi_processor_set_throttling_ptc;
        }
 
-       acpi_processor_get_tsd(pr);
+       /*
+        * If TSD package for one CPU can't be parsed successfully, it means
+        * that this CPU will have no coordination with other CPUs.
+        */
+       if (acpi_processor_get_tsd(pr)) {
+               pthrottling = &pr->throttling;
+               pthrottling->tsd_valid_flag = 0;
+               cpu_set(pr->id, pthrottling->shared_cpu_map);
+               pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
+       }
 
        /*
         * PIIX4 Errata: We don't support throttling on the original PIIX4.
index f136c7d3b3c234c0d5a5b4fabf19aa95df3733d1..1194105cc3cad977c5472a528ba8a261a870d2a8 100644 (file)
@@ -888,7 +888,7 @@ static void acpi_charger_remove(struct acpi_sbs *sbs)
 #endif
 }
 
-void acpi_sbs_callback(void *context)
+static void acpi_sbs_callback(void *context)
 {
        int id;
        struct acpi_sbs *sbs = context;
index fd40b6a1d639693a9160080b736c4c8d86cb909e..ae9a90438e2f32f497e207889bf4677c431c3383 100644 (file)
@@ -111,8 +111,8 @@ static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
                return -ETIME;
 }
 
-int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, u8 address,
-                   u8 command, u8 *data, u8 length)
+static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
+                                 u8 address, u8 command, u8 *data, u8 length)
 {
        int ret = -EFAULT, i;
        u8 temp, sz = 0;
index d9d531cce27f26e401ff920b8325968b5fd4fb37..3fac011f9cf964082b463ef20913542ca9bce173 100644 (file)
@@ -59,7 +59,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
                        count = snprintf(&modalias[len], size, "%s:",
                                         cid_list->id[i].value);
                        if (count < 0 || count >= size) {
-                               printk(KERN_ERR "acpi: %s cid[%i] exceeds event buffer size",
+                               printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size",
                                       acpi_dev->pnp.device_name, i);
                                break;
                        }
@@ -453,7 +453,7 @@ static int acpi_device_register(struct acpi_device *device,
        device->dev.release = &acpi_device_release;
        result = device_add(&device->dev);
        if(result) {
-               printk("Error adding device %s", device->dev.bus_id);
+               printk(KERN_ERR PREFIX "Error adding device %s", device->dev.bus_id);
                goto end;
        }
 
@@ -941,6 +941,15 @@ static int acpi_bay_match(struct acpi_device *device){
        return -ENODEV;
 }
 
+/*
+ * acpi_dock_match - see if a device has a _DCK method
+ */
+static int acpi_dock_match(struct acpi_device *device)
+{
+       acpi_handle tmp;
+       return acpi_get_handle(device->handle, "_DCK", &tmp);
+}
+
 static void acpi_device_set_id(struct acpi_device *device,
                               struct acpi_device *parent, acpi_handle handle,
                               int type)
@@ -950,13 +959,14 @@ static void acpi_device_set_id(struct acpi_device *device,
        char *hid = NULL;
        char *uid = NULL;
        struct acpi_compatible_id_list *cid_list = NULL;
+       const char *cid_add = NULL;
        acpi_status status;
 
        switch (type) {
        case ACPI_BUS_TYPE_DEVICE:
                status = acpi_get_object_info(handle, &buffer);
                if (ACPI_FAILURE(status)) {
-                       printk("%s: Error reading device info\n", __FUNCTION__);
+                       printk(KERN_ERR PREFIX "%s: Error reading device info\n", __FUNCTION__);
                        return;
                }
 
@@ -972,15 +982,18 @@ static void acpi_device_set_id(struct acpi_device *device,
                        device->flags.bus_address = 1;
                }
 
-               if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
-                       status = acpi_video_bus_match(device);
-                       if(ACPI_SUCCESS(status))
-                               hid = ACPI_VIDEO_HID;
+               /* If we have a video/bay/dock device, add our selfdefined
+                  HID to the CID list. Like that the video/bay/dock drivers
+                  will get autoloaded and the device might still match
+                  against another driver.
+               */
+               if (ACPI_SUCCESS(acpi_video_bus_match(device)))
+                       cid_add = ACPI_VIDEO_HID;
+               else if (ACPI_SUCCESS(acpi_bay_match(device)))
+                       cid_add = ACPI_BAY_HID;
+               else if (ACPI_SUCCESS(acpi_dock_match(device)))
+                       cid_add = ACPI_DOCK_HID;
 
-                       status = acpi_bay_match(device);
-                       if (ACPI_SUCCESS(status))
-                               hid = ACPI_BAY_HID;
-               }
                break;
        case ACPI_BUS_TYPE_POWER:
                hid = ACPI_POWER_HID;
@@ -1021,12 +1034,45 @@ static void acpi_device_set_id(struct acpi_device *device,
                strcpy(device->pnp.unique_id, uid);
                device->flags.unique_id = 1;
        }
-       if (cid_list) {
-               device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL);
-               if (device->pnp.cid_list)
-                       memcpy(device->pnp.cid_list, cid_list, cid_list->size);
-               else
-                       printk(KERN_ERR "Memory allocation error\n");
+       if (cid_list || cid_add) {
+               struct  acpi_compatible_id_list *list;
+               int size = 0;
+               int count = 0;
+
+               if (cid_list) {
+                       size = cid_list->size;
+               } else if (cid_add) {
+                       size = sizeof(struct acpi_compatible_id_list);
+                       cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
+                       if (!cid_list) {
+                               printk(KERN_ERR "Memory allocation error\n");
+                               kfree(buffer.pointer);
+                               return;
+                       } else {
+                               cid_list->count = 0;
+                               cid_list->size = size;
+                       }
+               }
+               if (cid_add)
+                       size += sizeof(struct acpi_compatible_id);
+               list = kmalloc(size, GFP_KERNEL);
+
+               if (list) {
+                       if (cid_list) {
+                               memcpy(list, cid_list, cid_list->size);
+                               count = cid_list->count;
+                       }
+                       if (cid_add) {
+                               strncpy(list->id[count].value, cid_add,
+                                       ACPI_MAX_CID_LENGTH);
+                               count++;
+                               device->flags.compatible_ids = 1;
+                       }
+                       list->size = size;
+                       list->count = count;
+                       device->pnp.cid_list = list;
+               } else
+                       printk(KERN_ERR PREFIX "Memory allocation error\n");
        }
 
        kfree(buffer.pointer);
@@ -1050,7 +1096,7 @@ static int acpi_device_set_context(struct acpi_device *device, int type)
                                          acpi_bus_data_handler, device);
 
                if (ACPI_FAILURE(status)) {
-                       printk("Error attaching device data\n");
+                       printk(KERN_ERR PREFIX "Error attaching device data\n");
                        result = -ENODEV;
                }
        }
@@ -1080,6 +1126,20 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
        return 0;
 }
 
+static int
+acpi_is_child_device(struct acpi_device *device,
+                       int (*matcher)(struct acpi_device *))
+{
+       int result = -ENODEV;
+
+       do {
+               if (ACPI_SUCCESS(matcher(device)))
+                       return AE_OK;
+       } while ((device = device->parent));
+
+       return result;
+}
+
 static int
 acpi_add_single_object(struct acpi_device **child,
                       struct acpi_device *parent, acpi_handle handle, int type,
@@ -1131,10 +1191,20 @@ acpi_add_single_object(struct acpi_device **child,
        case ACPI_BUS_TYPE_PROCESSOR:
        case ACPI_BUS_TYPE_DEVICE:
                result = acpi_bus_get_status(device);
-               if (ACPI_FAILURE(result) || !device->status.present) {
-                       result = -ENOENT;
+               if (ACPI_FAILURE(result)) {
+                       result = -ENODEV;
                        goto end;
                }
+               if (!device->status.present) {
+                       /* Bay and dock should be handled even if absent */
+                       if (!ACPI_SUCCESS(
+                            acpi_is_child_device(device, acpi_bay_match)) &&
+                           !ACPI_SUCCESS(
+                            acpi_is_child_device(device, acpi_dock_match))) {
+                                       result = -ENODEV;
+                                       goto end;
+                       }
+               }
                break;
        default:
                STRUCT_TO_INT(device->status) =
index 485de1347075c812c4c7dbd4347c67cca7bd67b3..293a1cbb47c05776b543894bc32ee145de0153b7 100644 (file)
@@ -170,7 +170,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
        /* Reprogram control registers and execute _BFS */
        acpi_leave_sleep_state_prep(acpi_state);
 
-       /* ACPI 3.0 specs (P62) says that it's the responsabilty
+       /* ACPI 3.0 specs (P62) says that it's the responsibility
         * of the OSPM to clear the status bit [ implying that the
         * POWER_BUTTON event should not reach userspace ]
         */
@@ -472,11 +472,20 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
        if (acpi_target_sleep_state == ACPI_STATE_S0 ||
            (wake && adev->wakeup.state.enabled &&
             adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
+               acpi_status status;
+
                acpi_method[3] = 'W';
-               acpi_evaluate_integer(handle, acpi_method, NULL, &d_max);
-               /* Sanity check */
-               if (d_max < d_min)
+               status = acpi_evaluate_integer(handle, acpi_method, NULL,
+                                               &d_max);
+               if (ACPI_FAILURE(status)) {
+                       d_max = d_min;
+               } else if (d_max < d_min) {
+                       /* Warn the user of the broken DSDT */
+                       printk(KERN_WARNING "ACPI: Wrong value from %s\n",
+                               acpi_method);
+                       /* Sanitize it */
                        d_min = d_max;
+               }
        }
 
        if (d_min_p)
index 1538355c266b4a5a26bf12d31424b7d0e1563127..f8df5217d477ee525c30f4c1050bf7cc8eb6e35b 100644 (file)
@@ -178,6 +178,9 @@ static int get_date_field(char **p, u32 * value)
         * Try to find delimeter, only to insert null.  The end of the
         * string won't have one, but is still valid.
         */
+       if (*p == NULL)
+               return result;
+
        next = strpbrk(*p, "- :");
        if (next)
                *next++ = '\0';
@@ -190,6 +193,8 @@ static int get_date_field(char **p, u32 * value)
 
        if (next)
                *p = next;
+       else
+               *p = NULL;
 
        return result;
 }
@@ -251,27 +256,6 @@ acpi_system_write_alarm(struct file *file,
        if ((result = get_date_field(&p, &sec)))
                goto end;
 
-       if (sec > 59) {
-               min += 1;
-               sec -= 60;
-       }
-       if (min > 59) {
-               hr += 1;
-               min -= 60;
-       }
-       if (hr > 23) {
-               day += 1;
-               hr -= 24;
-       }
-       if (day > 31) {
-               mo += 1;
-               day -= 31;
-       }
-       if (mo > 12) {
-               yr += 1;
-               mo -= 12;
-       }
-
        spin_lock_irq(&rtc_lock);
 
        rtc_control = CMOS_READ(RTC_CONTROL);
@@ -288,24 +272,24 @@ acpi_system_write_alarm(struct file *file,
        spin_unlock_irq(&rtc_lock);
 
        if (sec > 59) {
-               min++;
-               sec -= 60;
+               min += sec/60;
+               sec = sec%60;
        }
        if (min > 59) {
-               hr++;
-               min -= 60;
+               hr += min/60;
+               min = min%60;
        }
        if (hr > 23) {
-               day++;
-               hr -= 24;
+               day += hr/24;
+               hr = hr%24;
        }
        if (day > 31) {
-               mo++;
-               day -= 31;
+               mo += day/32;
+               day = day%32;
        }
        if (mo > 12) {
-               yr++;
-               mo -= 12;
+               yr += mo/13;
+               mo = mo%13;
        }
 
        spin_lock_irq(&rtc_lock);
index 5ffe0ea18967a82cf8a8ecb4fd64dd7362f125b6..55cf4c05bb74edc7714ddb4a000b729395feb291 100644 (file)
@@ -40,6 +40,8 @@ ACPI_MODULE_NAME("system");
 #define ACPI_SYSTEM_CLASS              "system"
 #define ACPI_SYSTEM_DEVICE_NAME                "System"
 
+u32 acpi_irq_handled;
+
 /*
  * Make ACPICA version work as module param
  */
@@ -166,6 +168,212 @@ static int acpi_system_sysfs_init(void)
        return 0;
 }
 
+/*
+ * Detailed ACPI IRQ counters in /sys/firmware/acpi/interrupts/
+ * See Documentation/ABI/testing/sysfs-firmware-acpi
+ */
+
+#define COUNT_GPE 0
+#define COUNT_SCI 1    /* acpi_irq_handled */
+#define COUNT_ERROR 2  /* other */
+#define NUM_COUNTERS_EXTRA 3
+
+static u32 *all_counters;
+static u32 num_gpes;
+static u32 num_counters;
+static struct attribute **all_attrs;
+static u32 acpi_gpe_count;
+
+static struct attribute_group interrupt_stats_attr_group = {
+       .name = "interrupts",
+};
+static struct kobj_attribute *counter_attrs;
+
+static int count_num_gpes(void)
+{
+       int count = 0;
+       struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+       struct acpi_gpe_block_info *gpe_block;
+       acpi_cpu_flags flags;
+
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+       gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+       while (gpe_xrupt_info) {
+               gpe_block = gpe_xrupt_info->gpe_block_list_head;
+               while (gpe_block) {
+                       count += gpe_block->register_count *
+                           ACPI_GPE_REGISTER_WIDTH;
+                       gpe_block = gpe_block->next;
+               }
+               gpe_xrupt_info = gpe_xrupt_info->next;
+       }
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+       return count;
+}
+
+static void delete_gpe_attr_array(void)
+{
+       u32 *tmp = all_counters;
+
+       all_counters = NULL;
+       kfree(tmp);
+
+       if (counter_attrs) {
+               int i;
+
+               for (i = 0; i < num_gpes; i++)
+                       kfree(counter_attrs[i].attr.name);
+
+               kfree(counter_attrs);
+       }
+       kfree(all_attrs);
+
+       return;
+}
+
+void acpi_os_gpe_count(u32 gpe_number)
+{
+       acpi_gpe_count++;
+
+       if (!all_counters)
+               return;
+
+       if (gpe_number < num_gpes)
+               all_counters[gpe_number]++;
+       else
+               all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+
+       return;
+}
+
+void acpi_os_fixed_event_count(u32 event_number)
+{
+       if (!all_counters)
+               return;
+
+       if (event_number < ACPI_NUM_FIXED_EVENTS)
+               all_counters[num_gpes + event_number]++;
+       else
+               all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+
+       return;
+}
+
+static ssize_t counter_show(struct kobject *kobj,
+       struct kobj_attribute *attr, char *buf)
+{
+       all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI] =
+               acpi_irq_handled;
+       all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] =
+               acpi_gpe_count;
+
+       return sprintf(buf, "%d\n", all_counters[attr - counter_attrs]);
+}
+
+/*
+ * counter_set() sets the specified counter.
+ * setting the total "sci" file to any value clears all counters.
+ */
+static ssize_t counter_set(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t size)
+{
+       int index = attr - counter_attrs;
+
+       if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
+               int i;
+               for (i = 0; i < num_counters; ++i)
+                       all_counters[i] = 0;
+               acpi_gpe_count = 0;
+               acpi_irq_handled = 0;
+
+       } else
+               all_counters[index] = strtoul(buf, NULL, 0);
+
+       return size;
+}
+
+void acpi_irq_stats_init(void)
+{
+       int i;
+
+       if (all_counters)
+               return;
+
+       num_gpes = count_num_gpes();
+       num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA;
+
+       all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1),
+                       GFP_KERNEL);
+       if (all_attrs == NULL)
+               return;
+
+       all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL);
+       if (all_counters == NULL)
+               goto fail;
+
+       counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters),
+                       GFP_KERNEL);
+       if (counter_attrs == NULL)
+               goto fail;
+
+       for (i = 0; i < num_counters; ++i) {
+               char buffer[10];
+               char *name;
+
+               if (i < num_gpes)
+                       sprintf(buffer, "gpe%02X", i);
+               else if (i == num_gpes + ACPI_EVENT_PMTIMER)
+                       sprintf(buffer, "ff_pmtimer");
+               else if (i == num_gpes + ACPI_EVENT_GLOBAL)
+                       sprintf(buffer, "ff_gbl_lock");
+               else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON)
+                       sprintf(buffer, "ff_pwr_btn");
+               else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON)
+                       sprintf(buffer, "ff_slp_btn");
+               else if (i == num_gpes + ACPI_EVENT_RTC)
+                       sprintf(buffer, "ff_rt_clk");
+               else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE)
+                       sprintf(buffer, "gpe_all");
+               else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI)
+                       sprintf(buffer, "sci");
+               else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR)
+                       sprintf(buffer, "error");
+               else
+                       sprintf(buffer, "bug%02X", i);
+
+               name = kzalloc(strlen(buffer) + 1, GFP_KERNEL);
+               if (name == NULL)
+                       goto fail;
+               strncpy(name, buffer, strlen(buffer) + 1);
+
+               counter_attrs[i].attr.name = name;
+               counter_attrs[i].attr.mode = 0644;
+               counter_attrs[i].show = counter_show;
+               counter_attrs[i].store = counter_set;
+
+               all_attrs[i] = &counter_attrs[i].attr;
+       }
+
+       interrupt_stats_attr_group.attrs = all_attrs;
+       if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group))
+               return;
+
+fail:
+       delete_gpe_attr_array();
+       return;
+}
+
+static void __exit interrupt_stats_exit(void)
+{
+       sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group);
+
+       delete_gpe_attr_array();
+
+       return;
+}
+
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
index 0a7d7afac255e505e1733c05a38c31a379344c70..7385efa61622c412d44cb3708bb26fdc559c64c7 100644 (file)
@@ -2,6 +2,6 @@
 # Makefile for all Linux ACPI interpreter subdirectories
 #
 
-obj-y := tbxface.o tbinstal.o  tbutils.o tbfind.o tbfadt.o
+obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
index cf8fa514189f52b1be4f8bfb3b9782ed64d34564..9ecb4b6c1e7d5d37b9d6ffd8691fff1efc46d4dd 100644 (file)
@@ -100,7 +100,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_find_rsdp
+ * FUNCTION:    acpi_find_root_pointer
  *
  * PARAMETERS:  table_address           - Where the table pointer is returned
  *
@@ -219,8 +219,6 @@ acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
        return_ACPI_STATUS(AE_NOT_FOUND);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_scan_memory_for_rsdp
index 5f79b44512120e489950f65a22d912aa88ed66ec..8d4b79b4f933c631281e23ce8b602e3bcbbf3d9f 100644 (file)
@@ -43,7 +43,7 @@
 #include <linux/seq_file.h>
 #include <linux/reboot.h>
 #include <asm/uaccess.h>
-
+#include <linux/thermal.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -65,9 +65,6 @@
 #define ACPI_THERMAL_MAX_ACTIVE        10
 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
 
-#define KELVIN_TO_CELSIUS(t)    (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
-#define CELSIUS_TO_KELVIN(t)   ((t+273)*10)
-
 #define _COMPONENT             ACPI_THERMAL_COMPONENT
 ACPI_MODULE_NAME("thermal");
 
@@ -195,6 +192,8 @@ struct acpi_thermal {
        struct acpi_thermal_trips trips;
        struct acpi_handle_list devices;
        struct timer_list timer;
+       struct thermal_zone_device *thermal_zone;
+       int tz_enabled;
        struct mutex lock;
 };
 
@@ -321,178 +320,226 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
        return 0;
 }
 
-static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
-{
-       acpi_status status = AE_OK;
-       int i = 0;
+#define ACPI_TRIPS_CRITICAL    0x01
+#define ACPI_TRIPS_HOT         0x02
+#define ACPI_TRIPS_PASSIVE     0x04
+#define ACPI_TRIPS_ACTIVE      0x08
+#define ACPI_TRIPS_DEVICES     0x10
 
+#define ACPI_TRIPS_REFRESH_THRESHOLDS  (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
+#define ACPI_TRIPS_REFRESH_DEVICES     ACPI_TRIPS_DEVICES
 
-       if (!tz)
-               return -EINVAL;
+#define ACPI_TRIPS_INIT      (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT |   \
+                             ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE |  \
+                             ACPI_TRIPS_DEVICES)
 
-       /* Critical Shutdown (required) */
-
-       status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,
-                                      &tz->trips.critical.temperature);
-       if (ACPI_FAILURE(status)) {
-               tz->trips.critical.flags.valid = 0;
-               ACPI_EXCEPTION((AE_INFO, status, "No critical threshold"));
-               return -ENODEV;
-       } else {
-               tz->trips.critical.flags.valid = 1;
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Found critical threshold [%lu]\n",
-                                 tz->trips.critical.temperature));
-       }
+/*
+ * This exception is thrown out in two cases:
+ * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
+ *   when re-evaluating the AML code.
+ * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
+ *   We need to re-bind the cooling devices of a thermal zone when this occurs.
+ */
+#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str)       \
+do {   \
+       if (flags != ACPI_TRIPS_INIT)   \
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,      \
+               "ACPI thermal trip point %s changed\n"  \
+               "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
+} while (0)
+
+static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
+{
+       acpi_status status = AE_OK;
+       struct acpi_handle_list devices;
+       int valid = 0;
+       int i;
 
-       if (tz->trips.critical.flags.valid == 1) {
-               if (crt == -1) {
+       /* Critical Shutdown (required) */
+       if (flag & ACPI_TRIPS_CRITICAL) {
+               status = acpi_evaluate_integer(tz->device->handle,
+                               "_CRT", NULL, &tz->trips.critical.temperature);
+               if (ACPI_FAILURE(status)) {
                        tz->trips.critical.flags.valid = 0;
-               } else if (crt > 0) {
-                       unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
-
-                       /*
-                        * Allow override to lower critical threshold
-                        */
-                       if (crt_k < tz->trips.critical.temperature)
-                               tz->trips.critical.temperature = crt_k;
+                       ACPI_EXCEPTION((AE_INFO, status,
+                                       "No critical threshold"));
+                       return -ENODEV;
+               } else {
+                       tz->trips.critical.flags.valid = 1;
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                       "Found critical threshold [%lu]\n",
+                                       tz->trips.critical.temperature));
+               }
+               if (tz->trips.critical.flags.valid == 1) {
+                       if (crt == -1) {
+                               tz->trips.critical.flags.valid = 0;
+                       } else if (crt > 0) {
+                               unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
+                               /*
+                                * Allow override to lower critical threshold
+                                */
+                               if (crt_k < tz->trips.critical.temperature)
+                                       tz->trips.critical.temperature = crt_k;
+                       }
                }
        }
 
        /* Critical Sleep (optional) */
-
-       status =
-           acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,
-                                 &tz->trips.hot.temperature);
-       if (ACPI_FAILURE(status)) {
-               tz->trips.hot.flags.valid = 0;
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
-       } else {
-               tz->trips.hot.flags.valid = 1;
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n",
-                                 tz->trips.hot.temperature));
-       }
-
-       /* Passive: Processors (optional) */
-
-       if (psv == -1) {
-               status = AE_SUPPORT;
-       } else if (psv > 0) {
-               tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
-               status = AE_OK;
-       } else {
+       if (flag & ACPI_TRIPS_HOT) {
                status = acpi_evaluate_integer(tz->device->handle,
-                       "_PSV", NULL, &tz->trips.passive.temperature);
+                               "_HOT", NULL, &tz->trips.hot.temperature);
+               if (ACPI_FAILURE(status)) {
+                       tz->trips.hot.flags.valid = 0;
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                       "No hot threshold\n"));
+               } else {
+                       tz->trips.hot.flags.valid = 1;
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                       "Found hot threshold [%lu]\n",
+                                       tz->trips.critical.temperature));
+               }
        }
 
-       if (ACPI_FAILURE(status)) {
-               tz->trips.passive.flags.valid = 0;
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
-       } else {
-               tz->trips.passive.flags.valid = 1;
-
-               status =
-                   acpi_evaluate_integer(tz->device->handle, "_TC1", NULL,
-                                         &tz->trips.passive.tc1);
-               if (ACPI_FAILURE(status))
-                       tz->trips.passive.flags.valid = 0;
-
-               status =
-                   acpi_evaluate_integer(tz->device->handle, "_TC2", NULL,
-                                         &tz->trips.passive.tc2);
-               if (ACPI_FAILURE(status))
-                       tz->trips.passive.flags.valid = 0;
+       /* Passive (optional) */
+       if (flag & ACPI_TRIPS_PASSIVE) {
+               valid = tz->trips.passive.flags.valid;
+               if (psv == -1) {
+                       status = AE_SUPPORT;
+               } else if (psv > 0) {
+                       tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
+                       status = AE_OK;
+               } else {
+                       status = acpi_evaluate_integer(tz->device->handle,
+                               "_PSV", NULL, &tz->trips.passive.temperature);
+               }
 
-               status =
-                   acpi_evaluate_integer(tz->device->handle, "_TSP", NULL,
-                                         &tz->trips.passive.tsp);
                if (ACPI_FAILURE(status))
                        tz->trips.passive.flags.valid = 0;
-
-               status =
-                   acpi_evaluate_reference(tz->device->handle, "_PSL", NULL,
-                                           &tz->trips.passive.devices);
+               else {
+                       tz->trips.passive.flags.valid = 1;
+                       if (flag == ACPI_TRIPS_INIT) {
+                               status = acpi_evaluate_integer(
+                                               tz->device->handle, "_TC1",
+                                               NULL, &tz->trips.passive.tc1);
+                               if (ACPI_FAILURE(status))
+                                       tz->trips.passive.flags.valid = 0;
+                               status = acpi_evaluate_integer(
+                                               tz->device->handle, "_TC2",
+                                               NULL, &tz->trips.passive.tc2);
+                               if (ACPI_FAILURE(status))
+                                       tz->trips.passive.flags.valid = 0;
+                               status = acpi_evaluate_integer(
+                                               tz->device->handle, "_TSP",
+                                               NULL, &tz->trips.passive.tsp);
+                               if (ACPI_FAILURE(status))
+                                       tz->trips.passive.flags.valid = 0;
+                       }
+               }
+       }
+       if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
+               memset(&devices, 0, sizeof(struct acpi_handle_list));
+               status = acpi_evaluate_reference(tz->device->handle, "_PSL",
+                                                       NULL, &devices);
                if (ACPI_FAILURE(status))
                        tz->trips.passive.flags.valid = 0;
-
-               if (!tz->trips.passive.flags.valid)
-                       printk(KERN_WARNING PREFIX "Invalid passive threshold\n");
                else
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "Found passive threshold [%lu]\n",
-                                         tz->trips.passive.temperature));
-       }
+                       tz->trips.passive.flags.valid = 1;
 
-       /* Active: Fans, etc. (optional) */
+               if (memcmp(&tz->trips.passive.devices, &devices,
+                               sizeof(struct acpi_handle_list))) {
+                       memcpy(&tz->trips.passive.devices, &devices,
+                               sizeof(struct acpi_handle_list));
+                       ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
+               }
+       }
+       if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
+               if (valid != tz->trips.passive.flags.valid)
+                               ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
+       }
 
+       /* Active (optional) */
        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
-
                char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
+               valid = tz->trips.active[i].flags.valid;
 
                if (act == -1)
-                       break;  /* disable all active trip points */
-
-               status = acpi_evaluate_integer(tz->device->handle,
-                       name, NULL, &tz->trips.active[i].temperature);
-
-               if (ACPI_FAILURE(status)) {
-                       if (i == 0)     /* no active trip points */
+                       break; /* disable all active trip points */
+
+               if (flag & ACPI_TRIPS_ACTIVE) {
+                       status = acpi_evaluate_integer(tz->device->handle,
+                               name, NULL, &tz->trips.active[i].temperature);
+                       if (ACPI_FAILURE(status)) {
+                               tz->trips.active[i].flags.valid = 0;
+                               if (i == 0)
+                                       break;
+                               if (act <= 0)
+                                       break;
+                               if (i == 1)
+                                       tz->trips.active[0].temperature =
+                                               CELSIUS_TO_KELVIN(act);
+                               else
+                                       /*
+                                        * Don't allow override higher than
+                                        * the next higher trip point
+                                        */
+                                       tz->trips.active[i - 1].temperature =
+                                               (tz->trips.active[i - 2].temperature <
+                                               CELSIUS_TO_KELVIN(act) ?
+                                               tz->trips.active[i - 2].temperature :
+                                               CELSIUS_TO_KELVIN(act));
                                break;
-                       if (act <= 0)   /* no override requested */
-                               break;
-                       if (i == 1) {   /* 1 trip point */
-                               tz->trips.active[0].temperature =
-                                       CELSIUS_TO_KELVIN(act);
-                       } else {        /* multiple trips */
-                               /*
-                                * Don't allow override higher than
-                                * the next higher trip point
-                                */
-                               tz->trips.active[i - 1].temperature =
-                                   (tz->trips.active[i - 2].temperature <
-                                       CELSIUS_TO_KELVIN(act) ?
-                                       tz->trips.active[i - 2].temperature :
-                                       CELSIUS_TO_KELVIN(act));
-                       }
-                       break;
+                       } else
+                               tz->trips.active[i].flags.valid = 1;
                }
 
                name[2] = 'L';
-               status =
-                   acpi_evaluate_reference(tz->device->handle, name, NULL,
-                                           &tz->trips.active[i].devices);
-               if (ACPI_SUCCESS(status)) {
-                       tz->trips.active[i].flags.valid = 1;
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "Found active threshold [%d]:[%lu]\n",
-                                         i, tz->trips.active[i].temperature));
-               } else
-                       ACPI_EXCEPTION((AE_INFO, status,
-                                       "Invalid active threshold [%d]", i));
+               if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
+                       memset(&devices, 0, sizeof(struct acpi_handle_list));
+                       status = acpi_evaluate_reference(tz->device->handle,
+                                               name, NULL, &devices);
+                       if (ACPI_FAILURE(status))
+                               tz->trips.active[i].flags.valid = 0;
+                       else
+                               tz->trips.active[i].flags.valid = 1;
+
+                       if (memcmp(&tz->trips.active[i].devices, &devices,
+                                       sizeof(struct acpi_handle_list))) {
+                               memcpy(&tz->trips.active[i].devices, &devices,
+                                       sizeof(struct acpi_handle_list));
+                               ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
+                       }
+               }
+               if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
+                       if (valid != tz->trips.active[i].flags.valid)
+                               ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
+
+               if (!tz->trips.active[i].flags.valid)
+                       break;
+       }
+
+       if (flag & ACPI_TRIPS_DEVICES) {
+               memset(&devices, 0, sizeof(struct acpi_handle_list));
+               status = acpi_evaluate_reference(tz->device->handle, "_TZD",
+                                               NULL, &devices);
+               if (memcmp(&tz->devices, &devices,
+                               sizeof(struct acpi_handle_list))) {
+                       memcpy(&tz->devices, &devices,
+                               sizeof(struct acpi_handle_list));
+                       ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
+               }
        }
 
        return 0;
 }
 
-static int acpi_thermal_get_devices(struct acpi_thermal *tz)
+static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
 {
-       acpi_status status = AE_OK;
-
-
-       if (!tz)
-               return -EINVAL;
-
-       status =
-           acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       return 0;
+       return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
 }
 
 static int acpi_thermal_critical(struct acpi_thermal *tz)
 {
-       if (!tz || !tz->trips.critical.flags.valid || nocrt)
+       if (!tz || !tz->trips.critical.flags.valid)
                return -EINVAL;
 
        if (tz->temperature >= tz->trips.critical.temperature) {
@@ -501,9 +548,6 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
        } else if (tz->trips.critical.flags.enabled)
                tz->trips.critical.flags.enabled = 0;
 
-       printk(KERN_EMERG
-              "Critical temperature reached (%ld C), shutting down.\n",
-              KELVIN_TO_CELSIUS(tz->temperature));
        acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
                                tz->trips.critical.flags.enabled);
        acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
@@ -511,14 +555,20 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
                                          ACPI_THERMAL_NOTIFY_CRITICAL,
                                          tz->trips.critical.flags.enabled);
 
-       orderly_poweroff(true);
+       /* take no action if nocrt is set */
+       if(!nocrt) {
+               printk(KERN_EMERG
+                       "Critical temperature reached (%ld C), shutting down.\n",
+                       KELVIN_TO_CELSIUS(tz->temperature));
+               orderly_poweroff(true);
+       }
 
        return 0;
 }
 
 static int acpi_thermal_hot(struct acpi_thermal *tz)
 {
-       if (!tz || !tz->trips.hot.flags.valid || nocrt)
+       if (!tz || !tz->trips.hot.flags.valid)
                return -EINVAL;
 
        if (tz->temperature >= tz->trips.hot.temperature) {
@@ -534,7 +584,7 @@ static int acpi_thermal_hot(struct acpi_thermal *tz)
                                          ACPI_THERMAL_NOTIFY_HOT,
                                          tz->trips.hot.flags.enabled);
 
-       /* TBD: Call user-mode "sleep(S4)" function */
+       /* TBD: Call user-mode "sleep(S4)" function if nocrt is cleared */
 
        return 0;
 }
@@ -732,6 +782,9 @@ static void acpi_thermal_check(void *data)
        if (result)
                goto unlock;
 
+       if (!tz->tz_enabled)
+               goto unlock;
+
        memset(&tz->state, 0, sizeof(tz->state));
 
        /*
@@ -825,6 +878,290 @@ static void acpi_thermal_check(void *data)
        mutex_unlock(&tz->lock);
 }
 
+/* sys I/F for generic thermal sysfs support */
+static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
+{
+       struct acpi_thermal *tz = thermal->devdata;
+
+       if (!tz)
+               return -EINVAL;
+
+       return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature));
+}
+
+static const char enabled[] = "kernel";
+static const char disabled[] = "user";
+static int thermal_get_mode(struct thermal_zone_device *thermal,
+                               char *buf)
+{
+       struct acpi_thermal *tz = thermal->devdata;
+
+       if (!tz)
+               return -EINVAL;
+
+       return sprintf(buf, "%s\n", tz->tz_enabled ?
+                       enabled : disabled);
+}
+
+static int thermal_set_mode(struct thermal_zone_device *thermal,
+                               const char *buf)
+{
+       struct acpi_thermal *tz = thermal->devdata;
+       int enable;
+
+       if (!tz)
+               return -EINVAL;
+
+       /*
+        * enable/disable thermal management from ACPI thermal driver
+        */
+       if (!strncmp(buf, enabled, sizeof enabled - 1))
+               enable = 1;
+       else if (!strncmp(buf, disabled, sizeof disabled - 1))
+               enable = 0;
+       else
+               return -EINVAL;
+
+       if (enable != tz->tz_enabled) {
+               tz->tz_enabled = enable;
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                       "%s ACPI thermal control\n",
+                       tz->tz_enabled ? enabled : disabled));
+               acpi_thermal_check(tz);
+       }
+       return 0;
+}
+
+static int thermal_get_trip_type(struct thermal_zone_device *thermal,
+                                int trip, char *buf)
+{
+       struct acpi_thermal *tz = thermal->devdata;
+       int i;
+
+       if (!tz || trip < 0)
+               return -EINVAL;
+
+       if (tz->trips.critical.flags.valid) {
+               if (!trip)
+                       return sprintf(buf, "critical\n");
+               trip--;
+       }
+
+       if (tz->trips.hot.flags.valid) {
+               if (!trip)
+                       return sprintf(buf, "hot\n");
+               trip--;
+       }
+
+       if (tz->trips.passive.flags.valid) {
+               if (!trip)
+                       return sprintf(buf, "passive\n");
+               trip--;
+       }
+
+       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
+               tz->trips.active[i].flags.valid; i++) {
+               if (!trip)
+                       return sprintf(buf, "active%d\n", i);
+               trip--;
+       }
+
+       return -EINVAL;
+}
+
+static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
+                                int trip, char *buf)
+{
+       struct acpi_thermal *tz = thermal->devdata;
+       int i;
+
+       if (!tz || trip < 0)
+               return -EINVAL;
+
+       if (tz->trips.critical.flags.valid) {
+               if (!trip)
+                       return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+                               tz->trips.critical.temperature));
+               trip--;
+       }
+
+       if (tz->trips.hot.flags.valid) {
+               if (!trip)
+                       return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+                                       tz->trips.hot.temperature));
+               trip--;
+       }
+
+       if (tz->trips.passive.flags.valid) {
+               if (!trip)
+                       return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+                                       tz->trips.passive.temperature));
+               trip--;
+       }
+
+       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
+               tz->trips.active[i].flags.valid; i++) {
+               if (!trip)
+                       return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+                                       tz->trips.active[i].temperature));
+               trip--;
+       }
+
+       return -EINVAL;
+}
+
+typedef int (*cb)(struct thermal_zone_device *, int,
+                 struct thermal_cooling_device *);
+static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
+                                       struct thermal_cooling_device *cdev,
+                                       cb action)
+{
+       struct acpi_device *device = cdev->devdata;
+       struct acpi_thermal *tz = thermal->devdata;
+       struct acpi_device *dev;
+       acpi_status status;
+       acpi_handle handle;
+       int i;
+       int j;
+       int trip = -1;
+       int result = 0;
+
+       if (tz->trips.critical.flags.valid)
+               trip++;
+
+       if (tz->trips.hot.flags.valid)
+               trip++;
+
+       if (tz->trips.passive.flags.valid) {
+               trip++;
+               for (i = 0; i < tz->trips.passive.devices.count;
+                   i++) {
+                       handle = tz->trips.passive.devices.handles[i];
+                       status = acpi_bus_get_device(handle, &dev);
+                       if (ACPI_SUCCESS(status) && (dev == device)) {
+                               result = action(thermal, trip, cdev);
+                               if (result)
+                                       goto failed;
+                       }
+               }
+       }
+
+       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+               if (!tz->trips.active[i].flags.valid)
+                       break;
+               trip++;
+               for (j = 0;
+                   j < tz->trips.active[i].devices.count;
+                   j++) {
+                       handle = tz->trips.active[i].devices.handles[j];
+                       status = acpi_bus_get_device(handle, &dev);
+                       if (ACPI_SUCCESS(status) && (dev == device)) {
+                               result = action(thermal, trip, cdev);
+                               if (result)
+                                       goto failed;
+                       }
+               }
+       }
+
+       for (i = 0; i < tz->devices.count; i++) {
+               handle = tz->devices.handles[i];
+               status = acpi_bus_get_device(handle, &dev);
+               if (ACPI_SUCCESS(status) && (dev == device)) {
+                       result = action(thermal, -1, cdev);
+                       if (result)
+                               goto failed;
+               }
+       }
+
+failed:
+       return result;
+}
+
+static int
+acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
+                                       struct thermal_cooling_device *cdev)
+{
+       return acpi_thermal_cooling_device_cb(thermal, cdev,
+                               thermal_zone_bind_cooling_device);
+}
+
+static int
+acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
+                                       struct thermal_cooling_device *cdev)
+{
+       return acpi_thermal_cooling_device_cb(thermal, cdev,
+                               thermal_zone_unbind_cooling_device);
+}
+
+static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
+       .bind = acpi_thermal_bind_cooling_device,
+       .unbind = acpi_thermal_unbind_cooling_device,
+       .get_temp = thermal_get_temp,
+       .get_mode = thermal_get_mode,
+       .set_mode = thermal_set_mode,
+       .get_trip_type = thermal_get_trip_type,
+       .get_trip_temp = thermal_get_trip_temp,
+};
+
+static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
+{
+       int trips = 0;
+       int result;
+       acpi_status status;
+       int i;
+
+       if (tz->trips.critical.flags.valid)
+               trips++;
+
+       if (tz->trips.hot.flags.valid)
+               trips++;
+
+       if (tz->trips.passive.flags.valid)
+               trips++;
+
+       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
+                       tz->trips.active[i].flags.valid; i++, trips++);
+       tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
+                                       trips, tz, &acpi_thermal_zone_ops);
+       if (!tz->thermal_zone)
+               return -ENODEV;
+
+       result = sysfs_create_link(&tz->device->dev.kobj,
+                                  &tz->thermal_zone->device.kobj, "thermal_zone");
+       if (result)
+               return result;
+
+       result = sysfs_create_link(&tz->thermal_zone->device.kobj,
+                                  &tz->device->dev.kobj, "device");
+       if (result)
+               return result;
+
+       status = acpi_attach_data(tz->device->handle,
+                                 acpi_bus_private_data_handler,
+                                 tz->thermal_zone);
+       if (ACPI_FAILURE(status)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                               "Error attaching device data\n"));
+               return -ENODEV;
+       }
+
+       tz->tz_enabled = 1;
+
+       printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n",
+                       tz->device->dev.bus_id, tz->thermal_zone->id);
+       return 0;
+}
+
+static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
+{
+       sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
+       sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
+       thermal_zone_device_unregister(tz->thermal_zone);
+       tz->thermal_zone = NULL;
+       acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler);
+}
+
+
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
@@ -1181,15 +1518,15 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
                acpi_thermal_check(tz);
                break;
        case ACPI_THERMAL_NOTIFY_THRESHOLDS:
-               acpi_thermal_get_trip_points(tz);
+               acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
                acpi_thermal_check(tz);
                acpi_bus_generate_proc_event(device, event, 0);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  device->dev.bus_id, event, 0);
                break;
        case ACPI_THERMAL_NOTIFY_DEVICES:
-               if (tz->flags.devices)
-                       acpi_thermal_get_devices(tz);
+               acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
+               acpi_thermal_check(tz);
                acpi_bus_generate_proc_event(device, event, 0);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  device->dev.bus_id, event, 0);
@@ -1232,11 +1569,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
        else
                acpi_thermal_get_polling_frequency(tz);
 
-       /* Get devices in this thermal zone [_TZD] (optional) */
-       result = acpi_thermal_get_devices(tz);
-       if (!result)
-               tz->flags.devices = 1;
-
        return 0;
 }
 
@@ -1260,13 +1592,19 @@ static int acpi_thermal_add(struct acpi_device *device)
        strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
        acpi_driver_data(device) = tz;
        mutex_init(&tz->lock);
+
+
        result = acpi_thermal_get_info(tz);
        if (result)
-               goto end;
+               goto free_memory;
+
+       result = acpi_thermal_register_thermal_zone(tz);
+       if (result)
+               goto free_memory;
 
        result = acpi_thermal_add_fs(device);
        if (result)
-               goto end;
+               goto unregister_thermal_zone;
 
        init_timer(&tz->timer);
 
@@ -1277,19 +1615,21 @@ static int acpi_thermal_add(struct acpi_device *device)
                                             acpi_thermal_notify, tz);
        if (ACPI_FAILURE(status)) {
                result = -ENODEV;
-               goto end;
+               goto remove_fs;
        }
 
        printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
               acpi_device_name(device), acpi_device_bid(device),
               KELVIN_TO_CELSIUS(tz->temperature));
+       goto end;
 
-      end:
-       if (result) {
-               acpi_thermal_remove_fs(device);
-               kfree(tz);
-       }
-
+remove_fs:
+       acpi_thermal_remove_fs(device);
+unregister_thermal_zone:
+       thermal_zone_device_unregister(tz->thermal_zone);
+free_memory:
+       kfree(tz);
+end:
        return result;
 }
 
@@ -1329,6 +1669,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
        }
 
        acpi_thermal_remove_fs(device);
+       acpi_thermal_unregister_thermal_zone(tz);
        mutex_destroy(&tz->lock);
        kfree(tz);
        return 0;
index 93ea8290b4f741d68986bce4f3d38ba9cf18983c..630c9a2c5b7bd78887c4eab62924fcde075925b8 100644 (file)
@@ -671,7 +671,6 @@ void acpi_ut_init_globals(void)
 
        /* GPE support */
 
-       acpi_gpe_count = 0;
        acpi_gbl_gpe_xrupt_list_head = NULL;
        acpi_gbl_gpe_fadt_blocks[0] = NULL;
        acpi_gbl_gpe_fadt_blocks[1] = NULL;
@@ -735,4 +734,3 @@ void acpi_ut_init_globals(void)
 
 ACPI_EXPORT_SYMBOL(acpi_dbg_level)
     ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
-    ACPI_EXPORT_SYMBOL(acpi_gpe_count)
index bd77e81e81c1ed00827db379766faae1485fe17d..7f714fa2a4547d284323d85441e60a9c6b61600f 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/seq_file.h>
 #include <linux/input.h>
 #include <linux/backlight.h>
+#include <linux/thermal.h>
 #include <linux/video_output.h>
 #include <asm/uaccess.h>
 
@@ -72,8 +73,12 @@ MODULE_AUTHOR("Bruno Ducrot");
 MODULE_DESCRIPTION("ACPI Video Driver");
 MODULE_LICENSE("GPL");
 
+static int brightness_switch_enabled = 1;
+module_param(brightness_switch_enabled, bool, 0644);
+
 static int acpi_video_bus_add(struct acpi_device *device);
 static int acpi_video_bus_remove(struct acpi_device *device, int type);
+static int acpi_video_resume(struct acpi_device *device);
 
 static const struct acpi_device_id video_device_ids[] = {
        {ACPI_VIDEO_HID, 0},
@@ -88,6 +93,7 @@ static struct acpi_driver acpi_video_bus = {
        .ops = {
                .add = acpi_video_bus_add,
                .remove = acpi_video_bus_remove,
+               .resume = acpi_video_resume,
                },
 };
 
@@ -179,6 +185,7 @@ struct acpi_video_device {
        struct acpi_device *dev;
        struct acpi_video_device_brightness *brightness;
        struct backlight_device *backlight;
+       struct thermal_cooling_device *cdev;
        struct output_device *output_dev;
 };
 
@@ -273,7 +280,6 @@ static void acpi_video_device_rebind(struct acpi_video_bus *video);
 static void acpi_video_device_bind(struct acpi_video_bus *video,
                                   struct acpi_video_device *device);
 static int acpi_video_device_enumerate(struct acpi_video_bus *video);
-static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
 static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
                        int level);
 static int acpi_video_device_lcd_get_level_current(
@@ -292,18 +298,26 @@ static int acpi_video_device_set_state(struct acpi_video_device *device, int sta
 static int acpi_video_get_brightness(struct backlight_device *bd)
 {
        unsigned long cur_level;
+       int i;
        struct acpi_video_device *vd =
                (struct acpi_video_device *)bl_get_data(bd);
        acpi_video_device_lcd_get_level_current(vd, &cur_level);
-       return (int) cur_level;
+       for (i = 2; i < vd->brightness->count; i++) {
+               if (vd->brightness->levels[i] == cur_level)
+                       /* The first two entries are special - see page 575
+                          of the ACPI spec 3.0 */
+                       return i-2;
+       }
+       return 0;
 }
 
 static int acpi_video_set_brightness(struct backlight_device *bd)
 {
-       int request_level = bd->props.brightness;
+       int request_level = bd->props.brightness+2;
        struct acpi_video_device *vd =
                (struct acpi_video_device *)bl_get_data(bd);
-       acpi_video_device_lcd_set_level(vd, request_level);
+       acpi_video_device_lcd_set_level(vd,
+                                       vd->brightness->levels[request_level]);
        return 0;
 }
 
@@ -334,6 +348,54 @@ static struct output_properties acpi_output_properties = {
        .set_state = acpi_video_output_set,
        .get_status = acpi_video_output_get,
 };
+
+
+/* thermal cooling device callbacks */
+static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+{
+       struct acpi_device *device = cdev->devdata;
+       struct acpi_video_device *video = acpi_driver_data(device);
+
+       return sprintf(buf, "%d\n", video->brightness->count - 3);
+}
+
+static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+{
+       struct acpi_device *device = cdev->devdata;
+       struct acpi_video_device *video = acpi_driver_data(device);
+       unsigned long level;
+       int state;
+
+       acpi_video_device_lcd_get_level_current(video, &level);
+       for (state = 2; state < video->brightness->count; state++)
+               if (level == video->brightness->levels[state])
+                       return sprintf(buf, "%d\n",
+                                      video->brightness->count - state - 1);
+
+       return -EINVAL;
+}
+
+static int
+video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+{
+       struct acpi_device *device = cdev->devdata;
+       struct acpi_video_device *video = acpi_driver_data(device);
+       int level;
+
+       if ( state >= video->brightness->count - 2)
+               return -EINVAL;
+
+       state = video->brightness->count - state;
+       level = video->brightness->levels[state -1];
+       return acpi_video_device_lcd_set_level(video, level);
+}
+
+static struct thermal_cooling_device_ops video_cooling_ops = {
+       .get_max_state = video_get_max_state,
+       .get_cur_state = video_get_cur_state,
+       .set_cur_state = video_set_cur_state,
+};
+
 /* --------------------------------------------------------------------------
                                Video Management
    -------------------------------------------------------------------------- */
@@ -652,7 +714,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
        kfree(obj);
 
        if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
-               unsigned long tmp;
+               int result;
                static int count = 0;
                char *name;
                name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
@@ -660,14 +722,30 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                        return;
 
                sprintf(name, "acpi_video%d", count++);
-               acpi_video_device_lcd_get_level_current(device, &tmp);
                device->backlight = backlight_device_register(name,
                        NULL, device, &acpi_backlight_ops);
-               device->backlight->props.max_brightness = max_level;
-               device->backlight->props.brightness = (int)tmp;
+               device->backlight->props.max_brightness = device->brightness->count-3;
+               device->backlight->props.brightness = acpi_video_get_brightness(device->backlight);
                backlight_update_status(device->backlight);
-
                kfree(name);
+
+               device->cdev = thermal_cooling_device_register("LCD",
+                                       device->dev, &video_cooling_ops);
+               if (device->cdev) {
+                       printk(KERN_INFO PREFIX
+                               "%s is registered as cooling_device%d\n",
+                               device->dev->dev.bus_id, device->cdev->id);
+                       result = sysfs_create_link(&device->dev->dev.kobj,
+                                         &device->cdev->device.kobj,
+                                         "thermal_cooling");
+                       if (result)
+                               printk(KERN_ERR PREFIX "Create sysfs link\n");
+                       result = sysfs_create_link(&device->cdev->device.kobj,
+                                         &device->dev->dev.kobj,
+                                         "device");
+                        if (result)
+                               printk(KERN_ERR PREFIX "Create sysfs link\n");
+               }
        }
        if (device->cap._DCS && device->cap._DSS){
                static int count = 0;
@@ -726,11 +804,40 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
 static int acpi_video_bus_check(struct acpi_video_bus *video)
 {
        acpi_status status = -ENOENT;
-
+       long device_id;
+       struct device *dev;
+       struct acpi_device *device;
 
        if (!video)
                return -EINVAL;
 
+       device = video->device;
+
+       status =
+           acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
+
+       if (!ACPI_SUCCESS(status))
+               return -ENODEV;
+
+       /* We need to attempt to determine whether the _ADR refers to a
+          PCI device or not. There's no terribly good way to do this,
+          so the best we can hope for is to assume that there'll never
+          be a video device in the host bridge */
+       if (device_id >= 0x10000) {
+               /* It looks like a PCI device. Does it exist? */
+               dev = acpi_get_physical_device(device->handle);
+       } else {
+               /* It doesn't look like a PCI device. Does its parent
+                  exist? */
+               acpi_handle phandle;
+               if (acpi_get_parent(device->handle, &phandle))
+                       return -ENODEV;
+               dev = acpi_get_physical_device(phandle);
+       }
+       if (!dev)
+               return -ENODEV;
+       put_device(dev);
+
        /* Since there is no HID, CID and so on for VGA driver, we have
         * to check well known required nodes.
         */
@@ -1256,8 +1363,37 @@ acpi_video_bus_write_DOS(struct file *file,
 
 static int acpi_video_bus_add_fs(struct acpi_device *device)
 {
+       long device_id;
+       int status;
        struct proc_dir_entry *entry = NULL;
        struct acpi_video_bus *video;
+       struct device *dev;
+
+       status =
+           acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
+
+       if (!ACPI_SUCCESS(status))
+               return -ENODEV;
+
+       /* We need to attempt to determine whether the _ADR refers to a
+          PCI device or not. There's no terribly good way to do this,
+          so the best we can hope for is to assume that there'll never
+          be a video device in the host bridge */
+       if (device_id >= 0x10000) {
+               /* It looks like a PCI device. Does it exist? */
+               dev = acpi_get_physical_device(device->handle);
+       } else {
+               /* It doesn't look like a PCI device. Does its parent
+                  exist? */
+               acpi_handle phandle;
+               if (acpi_get_parent(device->handle, &phandle))
+                       return -ENODEV;
+               dev = acpi_get_physical_device(phandle);
+       }
+       if (!dev)
+               return -ENODEV;
+       put_device(dev);
+
 
 
        video = acpi_driver_data(device);
@@ -1580,64 +1716,6 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
        return status;
 }
 
-/*
- *  Arg:
- *     video   : video bus device 
- *     event   : notify event
- *
- *  Return:
- *     < 0     : error
- *  
- *     1. Find out the current active output device.
- *     2. Identify the next output device to switch to.
- *     3. call _DSS to do actual switch.
- */
-
-static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
-{
-       struct list_head *node;
-       struct acpi_video_device *dev = NULL;
-       struct acpi_video_device *dev_next = NULL;
-       struct acpi_video_device *dev_prev = NULL;
-       unsigned long state;
-       int status = 0;
-
-       mutex_lock(&video->device_list_lock);
-
-       list_for_each(node, &video->video_device_list) {
-               dev = container_of(node, struct acpi_video_device, entry);
-               status = acpi_video_device_get_state(dev, &state);
-               if (state & 0x2) {
-                       dev_next = container_of(node->next,
-                                       struct acpi_video_device, entry);
-                       dev_prev = container_of(node->prev,
-                                       struct acpi_video_device, entry);
-                       goto out;
-               }
-       }
-
-       dev_next = container_of(node->next, struct acpi_video_device, entry);
-       dev_prev = container_of(node->prev, struct acpi_video_device, entry);
-
- out:
-       mutex_unlock(&video->device_list_lock);
-
-       switch (event) {
-       case ACPI_VIDEO_NOTIFY_CYCLE:
-       case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
-               acpi_video_device_set_state(dev, 0);
-               acpi_video_device_set_state(dev_next, 0x80000001);
-               break;
-       case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
-               acpi_video_device_set_state(dev, 0);
-               acpi_video_device_set_state(dev_prev, 0x80000001);
-       default:
-               break;
-       }
-
-       return status;
-}
-
 static int
 acpi_video_get_next_level(struct acpi_video_device *device,
                          u32 level_current, u32 event)
@@ -1729,6 +1807,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
                                            ACPI_DEVICE_NOTIFY,
                                            acpi_video_device_notify);
        backlight_device_unregister(device->backlight);
+       if (device->cdev) {
+               sysfs_remove_link(&device->dev->dev.kobj,
+                                 "thermal_cooling");
+               sysfs_remove_link(&device->cdev->device.kobj,
+                                 "device");
+               thermal_cooling_device_unregister(device->cdev);
+               device->cdev = NULL;
+       }
        video_output_unregister(device->output_dev);
 
        return 0;
@@ -1797,23 +1883,19 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
                                         * connector. */
                acpi_video_device_enumerate(video);
                acpi_video_device_rebind(video);
-               acpi_video_switch_output(video, event);
                acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_SWITCHVIDEOMODE;
                break;
 
        case ACPI_VIDEO_NOTIFY_CYCLE:   /* Cycle Display output hotkey pressed. */
-               acpi_video_switch_output(video, event);
                acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_SWITCHVIDEOMODE;
                break;
        case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:     /* Next Display output hotkey pressed. */
-               acpi_video_switch_output(video, event);
                acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_VIDEO_NEXT;
                break;
        case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:     /* previous Display output hotkey pressed. */
-               acpi_video_switch_output(video, event);
                acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_VIDEO_PREV;
                break;
@@ -1825,6 +1907,7 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
                break;
        }
 
+       acpi_notifier_call_chain(device, event, 0);
        input_report_key(input, keycode, 1);
        input_sync(input);
        input_report_key(input, keycode, 0);
@@ -1850,27 +1933,32 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
 
        switch (event) {
        case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:        /* Cycle brightness */
-               acpi_video_switch_brightness(video_device, event);
+               if (brightness_switch_enabled)
+                       acpi_video_switch_brightness(video_device, event);
                acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_BRIGHTNESS_CYCLE;
                break;
        case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:  /* Increase brightness */
-               acpi_video_switch_brightness(video_device, event);
+               if (brightness_switch_enabled)
+                       acpi_video_switch_brightness(video_device, event);
                acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_BRIGHTNESSUP;
                break;
        case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:  /* Decrease brightness */
-               acpi_video_switch_brightness(video_device, event);
+               if (brightness_switch_enabled)
+                       acpi_video_switch_brightness(video_device, event);
                acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_BRIGHTNESSDOWN;
                break;
        case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
-               acpi_video_switch_brightness(video_device, event);
+               if (brightness_switch_enabled)
+                       acpi_video_switch_brightness(video_device, event);
                acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_BRIGHTNESS_ZERO;
                break;
        case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:     /* display device off */
-               acpi_video_switch_brightness(video_device, event);
+               if (brightness_switch_enabled)
+                       acpi_video_switch_brightness(video_device, event);
                acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_DISPLAY_OFF;
                break;
@@ -1881,6 +1969,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
                break;
        }
 
+       acpi_notifier_call_chain(device, event, 0);
        input_report_key(input, keycode, 1);
        input_sync(input);
        input_report_key(input, keycode, 0);
@@ -1890,6 +1979,25 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
 }
 
 static int instance;
+static int acpi_video_resume(struct acpi_device *device)
+{
+       struct acpi_video_bus *video;
+       struct acpi_video_device *video_device;
+       int i;
+
+       if (!device || !acpi_driver_data(device))
+               return -EINVAL;
+
+       video = acpi_driver_data(device);
+
+       for (i = 0; i < video->attached_count; i++) {
+               video_device = video->attached_array[i].bind_info;
+               if (video_device && video_device->backlight)
+                       acpi_video_set_brightness(video_device->backlight);
+       }
+       return AE_OK;
+}
+
 static int acpi_video_bus_add(struct acpi_device *device)
 {
        acpi_status status;
diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c
new file mode 100644 (file)
index 0000000..36b84ab
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ *  ACPI-WMI mapping driver
+ *
+ *  Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
+ *
+ *  GUID parsing code from ldm.c is:
+ *   Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
+ *   Copyright (c) 2001-2007 Anton Altaparmakov
+ *   Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+ACPI_MODULE_NAME("wmi");
+MODULE_AUTHOR("Carlos Corbacho");
+MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
+MODULE_LICENSE("GPL");
+
+#define ACPI_WMI_CLASS "wmi"
+
+#undef PREFIX
+#define PREFIX "ACPI: WMI: "
+
+static DEFINE_MUTEX(wmi_data_lock);
+
+struct guid_block {
+       char guid[16];
+       union {
+               char object_id[2];
+               struct {
+                       unsigned char notify_id;
+                       unsigned char reserved;
+               };
+       };
+       u8 instance_count;
+       u8 flags;
+};
+
+struct wmi_block {
+       struct list_head list;
+       struct guid_block gblock;
+       acpi_handle handle;
+       wmi_notify_handler handler;
+       void *handler_data;
+};
+
+static struct wmi_block wmi_blocks;
+
+/*
+ * If the GUID data block is marked as expensive, we must enable and
+ * explicitily disable data collection.
+ */
+#define ACPI_WMI_EXPENSIVE   0x1
+#define ACPI_WMI_METHOD      0x2       /* GUID is a method */
+#define ACPI_WMI_STRING      0x4       /* GUID takes & returns a string */
+#define ACPI_WMI_EVENT       0x8       /* GUID is an event */
+
+static int acpi_wmi_remove(struct acpi_device *device, int type);
+static int acpi_wmi_add(struct acpi_device *device);
+
+static const struct acpi_device_id wmi_device_ids[] = {
+       {"PNP0C14", 0},
+       {"pnp0c14", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
+
+static struct acpi_driver acpi_wmi_driver = {
+       .name = "wmi",
+       .class = ACPI_WMI_CLASS,
+       .ids = wmi_device_ids,
+       .ops = {
+               .add = acpi_wmi_add,
+               .remove = acpi_wmi_remove,
+               },
+};
+
+/*
+ * GUID parsing functions
+ */
+
+/**
+ * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
+ * @src:  Pointer to at least 2 characters to convert.
+ *
+ * Convert a two character ASCII hex string to a number.
+ *
+ * Return:  0-255  Success, the byte was parsed correctly
+ *          -1     Error, an invalid character was supplied
+ */
+static int wmi_parse_hexbyte(const u8 *src)
+{
+       unsigned int x; /* For correct wrapping */
+       int h;
+
+       /* high part */
+       x = src[0];
+       if (x - '0' <= '9' - '0') {
+               h = x - '0';
+       } else if (x - 'a' <= 'f' - 'a') {
+               h = x - 'a' + 10;
+       } else if (x - 'A' <= 'F' - 'A') {
+               h = x - 'A' + 10;
+       } else {
+               return -1;
+       }
+       h <<= 4;
+
+       /* low part */
+       x = src[1];
+       if (x - '0' <= '9' - '0')
+               return h | (x - '0');
+       if (x - 'a' <= 'f' - 'a')
+               return h | (x - 'a' + 10);
+       if (x - 'A' <= 'F' - 'A')
+               return h | (x - 'A' + 10);
+       return -1;
+}
+
+/**
+ * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
+ * @src:   Memory block holding binary GUID (16 bytes)
+ * @dest:  Memory block to hold byte swapped binary GUID (16 bytes)
+ *
+ * Byte swap a binary GUID to match it's real GUID value
+ */
+static void wmi_swap_bytes(u8 *src, u8 *dest)
+{
+       int i;
+
+       for (i = 0; i <= 3; i++)
+               memcpy(dest + i, src + (3 - i), 1);
+
+       for (i = 0; i <= 1; i++)
+               memcpy(dest + 4 + i, src + (5 - i), 1);
+
+       for (i = 0; i <= 1; i++)
+               memcpy(dest + 6 + i, src + (7 - i), 1);
+
+       memcpy(dest + 8, src + 8, 8);
+}
+
+/**
+ * wmi_parse_guid - Convert GUID from ASCII to binary
+ * @src:   36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @dest:  Memory block to hold binary GUID (16 bytes)
+ *
+ * N.B. The GUID need not be NULL terminated.
+ *
+ * Return:  'true'   @dest contains binary GUID
+ *          'false'  @dest contents are undefined
+ */
+static bool wmi_parse_guid(const u8 *src, u8 *dest)
+{
+       static const int size[] = { 4, 2, 2, 2, 6 };
+       int i, j, v;
+
+       if (src[8]  != '-' || src[13] != '-' ||
+               src[18] != '-' || src[23] != '-')
+               return false;
+
+       for (j = 0; j < 5; j++, src++) {
+               for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
+                       v = wmi_parse_hexbyte(src);
+                       if (v < 0)
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+static bool find_guid(const char *guid_string, struct wmi_block **out)
+{
+       char tmp[16], guid_input[16];
+       struct wmi_block *wblock;
+       struct guid_block *block;
+       struct list_head *p;
+
+       wmi_parse_guid(guid_string, tmp);
+       wmi_swap_bytes(tmp, guid_input);
+
+       list_for_each(p, &wmi_blocks.list) {
+               wblock = list_entry(p, struct wmi_block, list);
+               block = &wblock->gblock;
+
+               if (memcmp(block->guid, guid_input, 16) == 0) {
+                       if (out)
+                               *out = wblock;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Exported WMI functions
+ */
+/**
+ * wmi_evaluate_method - Evaluate a WMI method
+ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @instance: Instance index
+ * @method_id: Method ID to call
+ * &in: Buffer containing input for the method call
+ * &out: Empty buffer to return the method results
+ *
+ * Call an ACPI-WMI method
+ */
+acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
+u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
+{
+       struct guid_block *block = NULL;
+       struct wmi_block *wblock = NULL;
+       acpi_handle handle;
+       acpi_status status;
+       struct acpi_object_list input;
+       union acpi_object params[3];
+       char method[4] = "WM";
+
+       if (!find_guid(guid_string, &wblock))
+               return AE_BAD_ADDRESS;
+
+       block = &wblock->gblock;
+       handle = wblock->handle;
+
+       if (!block->flags & ACPI_WMI_METHOD)
+               return AE_BAD_DATA;
+
+       if (block->instance_count < instance)
+               return AE_BAD_PARAMETER;
+
+       input.count = 2;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_INTEGER;
+       params[0].integer.value = instance;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = method_id;
+
+       if (in) {
+               input.count = 3;
+
+               if (block->flags & ACPI_WMI_STRING) {
+                       params[2].type = ACPI_TYPE_STRING;
+               } else {
+                       params[2].type = ACPI_TYPE_BUFFER;
+               }
+               params[2].buffer.length = in->length;
+               params[2].buffer.pointer = in->pointer;
+       }
+
+       strncat(method, block->object_id, 2);
+
+       status = acpi_evaluate_object(handle, method, &input, out);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(wmi_evaluate_method);
+
+/**
+ * wmi_query_block - Return contents of a WMI block
+ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @instance: Instance index
+ * &out: Empty buffer to return the contents of the data block to
+ *
+ * Return the contents of an ACPI-WMI data block to a buffer
+ */
+acpi_status wmi_query_block(const char *guid_string, u8 instance,
+struct acpi_buffer *out)
+{
+       struct guid_block *block = NULL;
+       struct wmi_block *wblock = NULL;
+       acpi_handle handle;
+       acpi_status status, wc_status = AE_ERROR;
+       struct acpi_object_list input, wc_input;
+       union acpi_object wc_params[1], wq_params[1];
+       char method[4];
+       char wc_method[4] = "WC";
+
+       if (!guid_string || !out)
+               return AE_BAD_PARAMETER;
+
+       if (!find_guid(guid_string, &wblock))
+               return AE_BAD_ADDRESS;
+
+       block = &wblock->gblock;
+       handle = wblock->handle;
+
+       if (block->instance_count < instance)
+               return AE_BAD_PARAMETER;
+
+       /* Check GUID is a data block */
+       if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
+               return AE_BAD_ADDRESS;
+
+       input.count = 1;
+       input.pointer = wq_params;
+       wq_params[0].type = ACPI_TYPE_INTEGER;
+       wq_params[0].integer.value = instance;
+
+       /*
+        * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
+        * enable collection.
+        */
+       if (block->flags & ACPI_WMI_EXPENSIVE) {
+               wc_input.count = 1;
+               wc_input.pointer = wc_params;
+               wc_params[0].type = ACPI_TYPE_INTEGER;
+               wc_params[0].integer.value = 1;
+
+               strncat(wc_method, block->object_id, 2);
+
+               /*
+                * Some GUIDs break the specification by declaring themselves
+                * expensive, but have no corresponding WCxx method. So we
+                * should not fail if this happens.
+                */
+               wc_status = acpi_evaluate_object(handle, wc_method,
+                       &wc_input, NULL);
+       }
+
+       strcpy(method, "WQ");
+       strncat(method, block->object_id, 2);
+
+       status = acpi_evaluate_object(handle, method, NULL, out);
+
+       /*
+        * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
+        * the WQxx method failed - we should disable collection anyway.
+        */
+       if ((block->flags & ACPI_WMI_EXPENSIVE) && wc_status) {
+               wc_params[0].integer.value = 0;
+               status = acpi_evaluate_object(handle,
+               wc_method, &wc_input, NULL);
+       }
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(wmi_query_block);
+
+/**
+ * wmi_set_block - Write to a WMI block
+ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @instance: Instance index
+ * &in: Buffer containing new values for the data block
+ *
+ * Write the contents of the input buffer to an ACPI-WMI data block
+ */
+acpi_status wmi_set_block(const char *guid_string, u8 instance,
+const struct acpi_buffer *in)
+{
+       struct guid_block *block = NULL;
+       struct wmi_block *wblock = NULL;
+       acpi_handle handle;
+       struct acpi_object_list input;
+       union acpi_object params[2];
+       char method[4] = "WS";
+
+       if (!guid_string || !in)
+               return AE_BAD_DATA;
+
+       if (!find_guid(guid_string, &wblock))
+               return AE_BAD_ADDRESS;
+
+       block = &wblock->gblock;
+       handle = wblock->handle;
+
+       if (block->instance_count < instance)
+               return AE_BAD_PARAMETER;
+
+       /* Check GUID is a data block */
+       if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
+               return AE_BAD_ADDRESS;
+
+       input.count = 2;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_INTEGER;
+       params[0].integer.value = instance;
+
+       if (block->flags & ACPI_WMI_STRING) {
+               params[1].type = ACPI_TYPE_STRING;
+       } else {
+               params[1].type = ACPI_TYPE_BUFFER;
+       }
+       params[1].buffer.length = in->length;
+       params[1].buffer.pointer = in->pointer;
+
+       strncat(method, block->object_id, 2);
+
+       return acpi_evaluate_object(handle, method, &input, NULL);
+}
+EXPORT_SYMBOL_GPL(wmi_set_block);
+
+/**
+ * wmi_install_notify_handler - Register handler for WMI events
+ * @handler: Function to handle notifications
+ * @data: Data to be returned to handler when event is fired
+ *
+ * Register a handler for events sent to the ACPI-WMI mapper device.
+ */
+acpi_status wmi_install_notify_handler(const char *guid,
+wmi_notify_handler handler, void *data)
+{
+       struct wmi_block *block;
+
+       if (!guid || !handler)
+               return AE_BAD_PARAMETER;
+
+       find_guid(guid, &block);
+       if (!block)
+               return AE_NOT_EXIST;
+
+       if (block->handler)
+               return AE_ALREADY_ACQUIRED;
+
+       block->handler = handler;
+       block->handler_data = data;
+
+       return AE_OK;
+}
+EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
+
+/**
+ * wmi_uninstall_notify_handler - Unregister handler for WMI events
+ *
+ * Unregister handler for events sent to the ACPI-WMI mapper device.
+ */
+acpi_status wmi_remove_notify_handler(const char *guid)
+{
+       struct wmi_block *block;
+
+       if (!guid)
+               return AE_BAD_PARAMETER;
+
+       find_guid(guid, &block);
+       if (!block)
+               return AE_NOT_EXIST;
+
+       if (!block->handler)
+               return AE_NULL_ENTRY;
+
+       block->handler = NULL;
+       block->handler_data = NULL;
+
+       return AE_OK;
+}
+EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
+
+/**
+ * wmi_get_event_data - Get WMI data associated with an event
+ *
+ * @event - Event to find
+ * &out - Buffer to hold event data
+ *
+ * Returns extra data associated with an event in WMI.
+ */
+acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
+{
+       struct acpi_object_list input;
+       union acpi_object params[1];
+       struct guid_block *gblock;
+       struct wmi_block *wblock;
+       struct list_head *p;
+
+       input.count = 1;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_INTEGER;
+       params[0].integer.value = event;
+
+       list_for_each(p, &wmi_blocks.list) {
+               wblock = list_entry(p, struct wmi_block, list);
+               gblock = &wblock->gblock;
+
+               if ((gblock->flags & ACPI_WMI_EVENT) &&
+                       (gblock->notify_id == event))
+                       return acpi_evaluate_object(wblock->handle, "_WED",
+                               &input, out);
+       }
+
+       return AE_NOT_FOUND;
+}
+EXPORT_SYMBOL_GPL(wmi_get_event_data);
+
+/**
+ * wmi_has_guid - Check if a GUID is available
+ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ *
+ * Check if a given GUID is defined by _WDG
+ */
+bool wmi_has_guid(const char *guid_string)
+{
+       return find_guid(guid_string, NULL);
+}
+EXPORT_SYMBOL_GPL(wmi_has_guid);
+
+/*
+ * Parse the _WDG method for the GUID data blocks
+ */
+static __init acpi_status parse_wdg(acpi_handle handle)
+{
+       struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object *obj;
+       struct guid_block *gblock;
+       struct wmi_block *wblock;
+       acpi_status status;
+       u32 i, total;
+
+       status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = (union acpi_object *) out.pointer;
+
+       if (obj->type != ACPI_TYPE_BUFFER)
+               return AE_ERROR;
+
+       total = obj->buffer.length / sizeof(struct guid_block);
+
+       gblock = kzalloc(obj->buffer.length, GFP_KERNEL);
+       if (!gblock)
+               return AE_NO_MEMORY;
+
+       memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
+
+       for (i = 0; i < total; i++) {
+               wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
+               if (!wblock)
+                       return AE_NO_MEMORY;
+
+               wblock->gblock = gblock[i];
+               wblock->handle = handle;
+               list_add_tail(&wblock->list, &wmi_blocks.list);
+       }
+
+       kfree(out.pointer);
+       kfree(gblock);
+
+       return status;
+}
+
+/*
+ * WMI can have EmbeddedControl access regions. In which case, we just want to
+ * hand these off to the EC driver.
+ */
+static acpi_status
+acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
+                     u32 bits, acpi_integer * value,
+                     void *handler_context, void *region_context)
+{
+       int result = 0, i = 0;
+       u8 temp = 0;
+
+       if ((address > 0xFF) || !value)
+               return AE_BAD_PARAMETER;
+
+       if (function != ACPI_READ && function != ACPI_WRITE)
+               return AE_BAD_PARAMETER;
+
+       if (bits != 8)
+               return AE_BAD_PARAMETER;
+
+       if (function == ACPI_READ) {
+               result = ec_read(address, &temp);
+               (*value) |= ((acpi_integer)temp) << i;
+       } else {
+               temp = 0xff & ((*value) >> i);
+               result = ec_write(address, temp);
+       }
+
+       switch (result) {
+       case -EINVAL:
+               return AE_BAD_PARAMETER;
+               break;
+       case -ENODEV:
+               return AE_NOT_FOUND;
+               break;
+       case -ETIME:
+               return AE_TIME;
+               break;
+       default:
+               return AE_OK;
+       }
+}
+
+static void acpi_wmi_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct guid_block *block;
+       struct wmi_block *wblock;
+       struct list_head *p;
+       struct acpi_device *device = data;
+
+       list_for_each(p, &wmi_blocks.list) {
+               wblock = list_entry(p, struct wmi_block, list);
+               block = &wblock->gblock;
+
+               if ((block->flags & ACPI_WMI_EVENT) &&
+                       (block->notify_id == event)) {
+                       if (wblock->handler)
+                               wblock->handler(event, wblock->handler_data);
+
+                       acpi_bus_generate_netlink_event(
+                               device->pnp.device_class, device->dev.bus_id,
+                               event, 0);
+                       break;
+               }
+       }
+}
+
+static int acpi_wmi_remove(struct acpi_device *device, int type)
+{
+       acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+               acpi_wmi_notify);
+
+       acpi_remove_address_space_handler(device->handle,
+                               ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
+
+       return 0;
+}
+
+static int __init acpi_wmi_add(struct acpi_device *device)
+{
+       acpi_status status;
+       int result = 0;
+
+       status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+               acpi_wmi_notify, device);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR PREFIX "Error installing notify handler\n");
+               return -ENODEV;
+       }
+
+       status = acpi_install_address_space_handler(device->handle,
+                                                   ACPI_ADR_SPACE_EC,
+                                                   &acpi_wmi_ec_space_handler,
+                                                   NULL, NULL);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       status = parse_wdg(device->handle);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR PREFIX "Error installing EC region handler\n");
+               return -ENODEV;
+       }
+
+       return result;
+}
+
+static int __init acpi_wmi_init(void)
+{
+       acpi_status result;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       INIT_LIST_HEAD(&wmi_blocks.list);
+
+       result = acpi_bus_register_driver(&acpi_wmi_driver);
+
+       if (result < 0) {
+               printk(KERN_INFO PREFIX "Error loading mapper\n");
+       } else {
+               printk(KERN_INFO PREFIX "Mapper loaded\n");
+       }
+
+       return result;
+}
+
+static void __exit acpi_wmi_exit(void)
+{
+       struct list_head *p, *tmp;
+       struct wmi_block *wblock;
+
+       acpi_bus_unregister_driver(&acpi_wmi_driver);
+
+       list_for_each_safe(p, tmp, &wmi_blocks.list) {
+               wblock = list_entry(p, struct wmi_block, list);
+
+               list_del(p);
+               kfree(wblock);
+       }
+
+       printk(KERN_INFO PREFIX "Mapper unloaded\n");
+}
+
+subsys_initcall(acpi_wmi_init);
+module_exit(acpi_wmi_exit);
index 78ebfffc77e33627b788e52e72094329e226f91a..4a7a059ebaf70b83f564430883ad517966c635de 100644 (file)
@@ -1202,8 +1202,10 @@ static int __devexit ace_of_remove(struct of_device *op)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id __devinit ace_of_match[] = {
-       { .compatible = "xilinx,xsysace", },
+static struct of_device_id ace_of_match[] __devinitdata = {
+       { .compatible = "xlnx,opb-sysace-1.00.b", },
+       { .compatible = "xlnx,opb-sysace-1.00.c", },
+       { .compatible = "xlnx,xps-sysace-1.00.a", },
        {},
 };
 MODULE_DEVICE_TABLE(of, ace_of_match);
index 8473b9f1da96168df571768b41889bf982c7e6a0..cac06bc1754b327f7e88605c4f1ed838d8187966 100644 (file)
@@ -558,7 +558,7 @@ static struct cdrom_device_ops viocd_dops = {
        .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM
 };
 
-static int __init find_capability(const char *type)
+static int find_capability(const char *type)
 {
        struct capability_entry *entry;
 
index 85bf9b2aa74ad5e0e09d75a0da8b1080b126b62e..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)"
@@ -841,6 +830,16 @@ config DTLK
          To compile this driver as a module, choose M here: the
          module will be called dtlk.
 
+config XILINX_HWICAP
+       tristate "Xilinx HWICAP Support"
+       depends on XILINX_VIRTEX
+       help
+         This option enables support for Xilinx Internal Configuration
+         Access Port (ICAP) driver.  The ICAP is used on Xilinx Virtex
+         FPGA platforms to partially reconfigure the FPGA at runtime.
+
+         If unsure, say N.
+
 config R3964
        tristate "Siemens R3964 line discipline"
        ---help---
index 96fc01eddefe805553ea1a834ba2f06a7f25c3b0..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
@@ -77,6 +76,7 @@ obj-$(CONFIG_EFI_RTC)         += efirtc.o
 obj-$(CONFIG_SGI_DS1286)       += ds1286.o
 obj-$(CONFIG_SGI_IP27_RTC)     += ip27-rtc.o
 obj-$(CONFIG_DS1302)           += ds1302.o
+obj-$(CONFIG_XILINX_HWICAP)    += xilinx_hwicap/
 ifeq ($(CONFIG_GENERIC_NVRAM),y)
   obj-$(CONFIG_NVRAM)  += generic_nvram.o
 else
index ba3058dd39a743b11f0a88b85acbce5e34e758a3..610d6fd5bb505a0dc568935477a9159a11a4ae1b 100644 (file)
@@ -38,7 +38,7 @@ config DRM_RADEON
          Choose this option if you have an ATI Radeon graphics card.  There
          are both PCI and AGP versions.  You don't need to choose this to
          run the Radeon in plain VGA mode.
-         
+
          If M is selected, the module will be called radeon.
 
 config DRM_I810
@@ -71,9 +71,9 @@ config DRM_I915
          852GM, 855GM 865G or 915G integrated graphics.  If M is selected, the
          module will be called i915.  AGP support is required for this driver
          to work. This driver is used by the Intel driver in X.org 6.8 and
-         XFree86 4.4 and above. If unsure, build this and i830 as modules and 
+         XFree86 4.4 and above. If unsure, build this and i830 as modules and
          the X server will load the correct one.
-       
+
 endchoice
 
 config DRM_MGA
@@ -88,7 +88,7 @@ config DRM_SIS
        tristate "SiS video cards"
        depends on DRM && AGP
        help
-         Choose this option if you have a SiS 630 or compatible video 
+         Choose this option if you have a SiS 630 or compatible video
           chipset. If M is selected the module will be called sis. AGP
           support is required for this driver to work.
 
@@ -105,4 +105,3 @@ config DRM_SAVAGE
        help
          Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
          chipset. If M is selected the module will be called savage.
-
index 6915a0599dfb09419ccb77a54aef0bc01cd06724..1283ded88ead726231924cc6c26868be6a85aa95 100644 (file)
@@ -38,5 +38,3 @@ obj-$(CONFIG_DRM_I915)  += i915.o
 obj-$(CONFIG_DRM_SIS)   += sis.o
 obj-$(CONFIG_DRM_SAVAGE)+= savage.o
 obj-$(CONFIG_DRM_VIA)  +=via.o
-
-
index af74cd79a279246800a81da33378fd9c46512a51..b5b3327225819fbf51df2daceca6d75fbd0dcf1b 100644 (file)
@@ -41,4 +41,3 @@ For specific information about kernel-level support, see:
 
     A Security Analysis of the Direct Rendering Infrastructure
     http://dri.sourceforge.net/doc/security_low_level.html
-
index 3345641ff904771a640e43cd4aec80674482cb0f..d352dbb4ccf7423f9bddca0bb9cc83cc055164f4 100644 (file)
@@ -41,7 +41,7 @@ static void *drm_ati_alloc_pcigart_table(int order)
        struct page *page;
        int i;
 
-       DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order);
+       DRM_DEBUG("%d order\n", order);
 
        address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
                                   order);
@@ -54,7 +54,7 @@ static void *drm_ati_alloc_pcigart_table(int order)
        for (i = 0; i < order; i++, page++)
                SetPageReserved(page);
 
-       DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address);
+       DRM_DEBUG("returning 0x%08lx\n", address);
        return (void *)address;
 }
 
@@ -63,7 +63,7 @@ static void drm_ati_free_pcigart_table(void *address, int order)
        struct page *page;
        int i;
        int num_pages = 1 << order;
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        page = virt_to_page((unsigned long)address);
 
index 82fb3d0d2785c5bf563b79fdcd39f782a8f48624..3a05c6d5ebe1f9306bca6a3e11740d54b9e6e5ef 100644 (file)
@@ -202,7 +202,8 @@ enum drm_map_flags {
        _DRM_KERNEL = 0x08,          /**< kernel requires access */
        _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */
        _DRM_CONTAINS_LOCK = 0x20,   /**< SHM page that contains lock */
-       _DRM_REMOVABLE = 0x40        /**< Removable mapping */
+       _DRM_REMOVABLE = 0x40,       /**< Removable mapping */
+       _DRM_DRIVER = 0x80           /**< Managed by driver */
 };
 
 struct drm_ctx_priv_map {
index dde02a15fa59d0f584dbf4bd63feaede1803afe6..19d3be5c4b2d73f9457834102e7ac25cc769cc4d 100644 (file)
@@ -292,7 +292,6 @@ struct drm_magic_entry {
        struct list_head head;
        struct drm_hash_item hash_item;
        struct drm_file *priv;
-       struct drm_magic_entry *next;
 };
 
 struct drm_vma_entry {
@@ -388,8 +387,8 @@ struct drm_file {
        struct drm_head *head;
        int remove_auth_on_close;
        unsigned long lock_count;
-       void *driver_priv;
        struct file *filp;
+       void *driver_priv;
 };
 
 /** Wait queue */
@@ -401,11 +400,9 @@ struct drm_queue {
        wait_queue_head_t read_queue;   /**< Processes waiting on block_read */
        atomic_t block_write;           /**< Queue blocked for writes */
        wait_queue_head_t write_queue;  /**< Processes waiting on block_write */
-#if 1
        atomic_t total_queued;          /**< Total queued statistic */
        atomic_t total_flushed;         /**< Total flushes statistic */
        atomic_t total_locks;           /**< Total locks statistics */
-#endif
        enum drm_ctx_flags flags;       /**< Context preserving and 2D-only */
        struct drm_waitlist waitlist;   /**< Pending buffers */
        wait_queue_head_t flush_queue;  /**< Processes waiting until flush */
@@ -416,7 +413,8 @@ struct drm_queue {
  */
 struct drm_lock_data {
        struct drm_hw_lock *hw_lock;    /**< Hardware lock */
-       struct drm_file *file_priv;     /**< File descr of lock holder (0=kernel) */
+       /** Private of lock holder's file (NULL=kernel) */
+       struct drm_file *file_priv;
        wait_queue_head_t lock_queue;   /**< Queue of blocked processes */
        unsigned long lock_time;        /**< Time of last lock in jiffies */
        spinlock_t spinlock;
@@ -491,6 +489,27 @@ struct drm_sigdata {
        struct drm_hw_lock *lock;
 };
 
+
+/*
+ * Generic memory manager structs
+ */
+
+struct drm_mm_node {
+       struct list_head fl_entry;
+       struct list_head ml_entry;
+       int free;
+       unsigned long start;
+       unsigned long size;
+       struct drm_mm *mm;
+       void *private;
+};
+
+struct drm_mm {
+       struct list_head fl_entry;
+       struct list_head ml_entry;
+};
+
+
 /**
  * Mappings list
  */
@@ -498,7 +517,7 @@ struct drm_map_list {
        struct list_head head;          /**< list head */
        struct drm_hash_item hash;
        struct drm_map *map;                    /**< mapping */
-       unsigned int user_token;
+       uint64_t user_token;
 };
 
 typedef struct drm_map drm_local_map_t;
@@ -536,24 +555,6 @@ struct drm_ati_pcigart_info {
        int table_size;
 };
 
-/*
- * Generic memory manager structs
- */
-struct drm_mm_node {
-       struct list_head fl_entry;
-       struct list_head ml_entry;
-       int free;
-       unsigned long start;
-       unsigned long size;
-       struct drm_mm *mm;
-       void *private;
-};
-
-struct drm_mm {
-       struct list_head fl_entry;
-       struct list_head ml_entry;
-};
-
 /**
  * DRM driver structure. This structure represent the common code for
  * a family of cards. There will one drm_device for each card present
@@ -567,6 +568,8 @@ struct drm_driver {
        void (*postclose) (struct drm_device *, struct drm_file *);
        void (*lastclose) (struct drm_device *);
        int (*unload) (struct drm_device *);
+       int (*suspend) (struct drm_device *);
+       int (*resume) (struct drm_device *);
        int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
        void (*dma_ready) (struct drm_device *);
        int (*dma_quiescent) (struct drm_device *);
@@ -642,6 +645,7 @@ struct drm_head {
  * may contain multiple heads.
  */
 struct drm_device {
+       struct device dev;              /**< Linux device */
        char *unique;                   /**< Unique identifier: e.g., busid */
        int unique_len;                 /**< Length of unique field */
        char *devname;                  /**< For /proc/interrupts */
@@ -750,7 +754,6 @@ struct drm_device {
        struct pci_controller *hose;
 #endif
        struct drm_sg_mem *sg;  /**< Scatter gather memory */
-       unsigned long *ctx_bitmap;      /**< context bitmap */
        void *dev_private;              /**< device private data */
        struct drm_sigdata sigdata;        /**< For block_all_signals */
        sigset_t sigmask;
@@ -847,6 +850,8 @@ extern int drm_release(struct inode *inode, struct file *filp);
 
                                /* Mapping support (drm_vm.h) */
 extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
+extern unsigned long drm_core_get_map_ofs(struct drm_map * map);
+extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
 extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
 
                                /* Memory management support (drm_memory.h) */
@@ -1061,11 +1066,11 @@ extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
 extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
 
                               /* sysfs support (drm_sysfs.c) */
+struct drm_sysfs_class;
 extern struct class *drm_sysfs_create(struct module *owner, char *name);
-extern void drm_sysfs_destroy(struct class *cs);
-extern struct class_device *drm_sysfs_device_add(struct class *cs,
-                                                struct drm_head *head);
-extern void drm_sysfs_device_remove(struct class_device *class_dev);
+extern void drm_sysfs_destroy(void);
+extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head);
+extern void drm_sysfs_device_remove(struct drm_device *dev);
 
 /*
  * Basic memory manager support (drm_mm.c)
@@ -1073,7 +1078,7 @@ extern void drm_sysfs_device_remove(struct class_device *class_dev);
 extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
                                       unsigned long size,
                                       unsigned alignment);
-void drm_mm_put_block(struct drm_mm_node * cur);
+extern void drm_mm_put_block(struct drm_mm_node * cur);
 extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, unsigned long size,
                                         unsigned alignment, int best_match);
 extern int drm_mm_init(struct drm_mm *mm, unsigned long start, unsigned long size);
@@ -1144,8 +1149,5 @@ extern void *drm_calloc(size_t nmemb, size_t size, int area);
 
 /*@}*/
 
-extern unsigned long drm_core_get_map_ofs(struct drm_map * map);
-extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
-
 #endif                         /* __KERNEL__ */
 #endif
index 214f4fbcba73e5746f63cde6dd3605416126e7b2..9468c7889ff1a24e83d78a3434c5498bd6265d08 100644 (file)
@@ -166,7 +166,6 @@ int drm_agp_enable(struct drm_device * dev, struct drm_agp_mode mode)
 
        dev->agp->mode = mode.mode;
        agp_enable(dev->agp->bridge, mode.mode);
-       dev->agp->base = dev->agp->agp_info.aper_base;
        dev->agp->enabled = 1;
        return 0;
 }
@@ -417,7 +416,7 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev)
        INIT_LIST_HEAD(&head->memory);
        head->cant_use_aperture = head->agp_info.cant_use_aperture;
        head->page_mask = head->agp_info.page_mask;
-
+       head->base = head->agp_info.aper_base;
        return head;
 }
 
index d24a6c2c2c24e10f33d7498fccd30e16a8574ec0..bde64b84166e1d783a2c5a8ece1816c483e76f0b 100644 (file)
@@ -184,7 +184,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                                return -ENOMEM;
                        }
                }
-                               
+
                break;
        case _DRM_SHM:
                list = drm_find_matching_map(dev, map);
@@ -229,11 +229,17 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
 #ifdef __alpha__
                map->offset += dev->hose->mem_space->start;
 #endif
-               /* Note: dev->agp->base may actually be 0 when the DRM
-                * is not in control of AGP space. But if user space is
-                * it should already have added the AGP base itself.
+               /* In some cases (i810 driver), user space may have already
+                * added the AGP base itself, because dev->agp->base previously
+                * only got set during AGP enable.  So, only add the base
+                * address if the map's offset isn't already within the
+                * aperture.
                 */
-               map->offset += dev->agp->base;
+               if (map->offset < dev->agp->base ||
+                   map->offset > dev->agp->base +
+                   dev->agp->agp_info.aper_size * 1024 * 1024 - 1) {
+                       map->offset += dev->agp->base;
+               }
                map->mtrr = dev->agp->agp_mtrr; /* for getmap */
 
                /* This assumes the DRM is in total control of AGP space.
@@ -429,6 +435,7 @@ int drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
 
        return ret;
 }
+EXPORT_SYMBOL(drm_rmmap);
 
 /* The rmmap ioctl appears to be unnecessary.  All mappings are torn down on
  * the last close of the device, and this is necessary for cleanup when things
@@ -814,9 +821,9 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
        page_count = 0;
 
        while (entry->buf_count < count) {
-               
+
                dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful);
-               
+
                if (!dmah) {
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
@@ -1592,5 +1599,3 @@ int drm_order(unsigned long size)
        return order;
 }
 EXPORT_SYMBOL(drm_order);
-
-
index 17fe69e7bfc19a4b69b2577402e781c93784e4db..d505f695421fbeff447435c450a2882e40133227 100644 (file)
@@ -159,7 +159,7 @@ int drm_getsareactx(struct drm_device *dev, void *data,
        request->handle = NULL;
        list_for_each_entry(_entry, &dev->maplist, head) {
                if (_entry->map == map) {
-                       request->handle = 
+                       request->handle =
                            (void *)(unsigned long)_entry->user_token;
                        break;
                }
index 44a46268b02b138c310c345b6ed6ecbdad7599f3..0e7af53c87deda41d66e61957732b64586d1391d 100644 (file)
@@ -200,8 +200,10 @@ int drm_lastclose(struct drm_device * dev)
        }
 
        list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
-               drm_rmmap_locked(dev, r_list->map);
-               r_list = NULL;
+               if (!(r_list->map->flags & _DRM_DRIVER)) {
+                       drm_rmmap_locked(dev, r_list->map);
+                       r_list = NULL;
+               }
        }
 
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {
@@ -255,8 +257,6 @@ int drm_init(struct drm_driver *driver)
 
        DRM_DEBUG("\n");
 
-       drm_mem_init();
-
        for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
                pid = (struct pci_device_id *)&driver->pci_driver.id_table[i];
 
@@ -293,10 +293,6 @@ static void drm_cleanup(struct drm_device * dev)
 
        drm_lastclose(dev);
 
-       drm_ht_remove(&dev->map_hash);
-
-       drm_ctxbitmap_cleanup(dev);
-
        if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
            dev->agp && dev->agp->agp_mtrr >= 0) {
                int retval;
@@ -314,6 +310,9 @@ static void drm_cleanup(struct drm_device * dev)
        if (dev->driver->unload)
                dev->driver->unload(dev);
 
+       drm_ht_remove(&dev->map_hash);
+       drm_ctxbitmap_cleanup(dev);
+
        drm_put_head(&dev->primary);
        if (drm_put_dev(dev))
                DRM_ERROR("Cannot unload module\n");
@@ -383,22 +382,24 @@ static int __init drm_core_init(void)
                goto err_p3;
        }
 
+       drm_mem_init();
+
        DRM_INFO("Initialized %s %d.%d.%d %s\n",
                 CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
        return 0;
-      err_p3:
-       drm_sysfs_destroy(drm_class);
-      err_p2:
+err_p3:
+       drm_sysfs_destroy();
+err_p2:
        unregister_chrdev(DRM_MAJOR, "drm");
        drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB);
-      err_p1:
+err_p1:
        return ret;
 }
 
 static void __exit drm_core_exit(void)
 {
        remove_proc_entry("dri", NULL);
-       drm_sysfs_destroy(drm_class);
+       drm_sysfs_destroy();
 
        unregister_chrdev(DRM_MAJOR, "drm");
 
@@ -494,23 +495,25 @@ int drm_ioctl(struct inode *inode, struct file *filp,
        } else {
                if (cmd & (IOC_IN | IOC_OUT)) {
                        kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
-                       if (!kdata)
-                               return -ENOMEM;
+                       if (!kdata) {
+                               retcode = -ENOMEM;
+                               goto err_i1;
+                       }
                }
 
                if (cmd & IOC_IN) {
                        if (copy_from_user(kdata, (void __user *)arg,
                                           _IOC_SIZE(cmd)) != 0) {
-                               retcode = -EACCES;
+                               retcode = -EFAULT;
                                goto err_i1;
                        }
                }
                retcode = func(dev, kdata, file_priv);
 
-               if (cmd & IOC_OUT) {
+               if ((retcode == 0) && (cmd & IOC_OUT)) {
                        if (copy_to_user((void __user *)arg, kdata,
                                         _IOC_SIZE(cmd)) != 0)
-                               retcode = -EACCES;
+                               retcode = -EFAULT;
                }
        }
 
index 4b8e7db5a23256452bff323f1d1b6acd0de34dc2..33160673a7b7846406400226665ae68c409e5e73 100644 (file)
@@ -80,7 +80,7 @@ void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
        }
 }
 
-static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht, 
+static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht,
                                          unsigned long key)
 {
        struct drm_hash_item *entry;
@@ -129,7 +129,7 @@ int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
 }
 
 /*
- * Just insert an item and return any "bits" bit key that hasn't been 
+ * Just insert an item and return any "bits" bit key that hasn't been
  * used before.
  */
 int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item,
@@ -200,4 +200,3 @@ void drm_ht_remove(struct drm_open_hash *ht)
                ht->table = NULL;
        }
 }
-
index 573e333ac4573168b6e073847f7e4ce88c1ca63d..cd2b189e1be6caac74fd2402d1d84d4119fbca22 100644 (file)
@@ -65,4 +65,3 @@ extern void drm_ht_remove(struct drm_open_hash *ht);
 
 
 #endif
-
index 2286f3312c5c0cbe27d1b4daa3803c1b1279b339..90f5a8d9bdcb67057ecf97301dee8d2f5ceb1566 100644 (file)
@@ -1051,8 +1051,12 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        drm_ioctl_compat_t *fn;
        int ret;
 
+       /* Assume that ioctls without an explicit compat routine will just
+        * work.  This may not always be a good assumption, but it's better
+        * than always failing.
+        */
        if (nr >= ARRAY_SIZE(drm_compat_ioctls))
-               return -ENOTTY;
+               return drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
 
        fn = drm_compat_ioctls[nr];
 
index 3cbebf868e6832c2e61fa1885da3b970132be038..16829fb3089d8adbfadda119d427e65bcaa8157c 100644 (file)
@@ -234,26 +234,23 @@ int drm_getclient(struct drm_device *dev, void *data,
 
        idx = client->idx;
        mutex_lock(&dev->struct_mutex);
-       
-       if (list_empty(&dev->filelist)) {
-               mutex_unlock(&dev->struct_mutex);
-               return -EINVAL;
-       }
 
        i = 0;
        list_for_each_entry(pt, &dev->filelist, lhead) {
-               if (i++ >= idx)
-                       break;
+               if (i++ >= idx) {
+                       client->auth = pt->authenticated;
+                       client->pid = pt->pid;
+                       client->uid = pt->uid;
+                       client->magic = pt->magic;
+                       client->iocs = pt->ioctl_count;
+                       mutex_unlock(&dev->struct_mutex);
+
+                       return 0;
+               }
        }
-
-       client->auth = pt->authenticated;
-       client->pid = pt->pid;
-       client->uid = pt->uid;
-       client->magic = pt->magic;
-       client->iocs = pt->ioctl_count;
        mutex_unlock(&dev->struct_mutex);
 
-       return 0;
+       return -EINVAL;
 }
 
 /**
index 05eae63f85baf173efe6473caccf12f8fde75139..089c015c01d148234fcd24abac9f935c9fd185ef 100644 (file)
@@ -107,7 +107,7 @@ static int drm_irq_install(struct drm_device * dev)
        dev->irq_enabled = 1;
        mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq);
+       DRM_DEBUG("irq=%d\n", dev->irq);
 
        if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
                init_waitqueue_head(&dev->vbl_queue);
@@ -164,7 +164,7 @@ int drm_irq_uninstall(struct drm_device * dev)
        if (!irq_enabled)
                return -EINVAL;
 
-       DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq);
+       DRM_DEBUG("irq=%d\n", dev->irq);
 
        dev->driver->irq_uninstall(dev);
 
index 93019901bd307c21c30e992f3d7a1f14bde31636..845081b44f637fbd2ba538a83155fa58b68423d8 100644 (file)
@@ -179,4 +179,3 @@ void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
                iounmap(map->handle);
 }
 EXPORT_SYMBOL(drm_core_ioremapfree);
-
index 86f4eb61a6a46c2a26247852231e5a612bf1a73e..dcff9e9b52e327016ee53590a98ea8b21d44d362 100644 (file)
@@ -293,4 +293,3 @@ void drm_mm_takedown(struct drm_mm * mm)
 
        drm_free(entry, sizeof(*entry), DRM_MEM_MM);
 }
-
index daa69c9d8977b9cf8055c082eca364abd13b5635..8dbd2572b7c3bc558bee3f6f3b18b1989c69e5fb 100644 (file)
@@ -69,9 +69,9 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
 #define DRM_COPY_TO_USER(arg1, arg2, arg3)             \
        copy_to_user(arg1, arg2, arg3)
 /* Macros for copyfrom user, but checking readability only once */
-#define DRM_VERIFYAREA_READ( uaddr, size )             \
+#define DRM_VERIFYAREA_READ( uaddr, size )             \
        (access_ok( VERIFY_READ, uaddr, size ) ? 0 : -EFAULT)
-#define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3)         \
+#define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \
        __copy_from_user(arg1, arg2, arg3)
 #define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3)   \
        __copy_to_user(arg1, arg2, arg3)
index 43d3c42df360552a47e6dc9ecbf3c0c3f1839e3c..f524688436786e9d4a3dbdd4f1c532c77dd36ae5 100644 (file)
        {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x710A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x710B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x710C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x710E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x710F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7143, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x714A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x714B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x714C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x714D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x714E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x714F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x715E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x715F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7183, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7186, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7187, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7188, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x718A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x718B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x718C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x718D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x718F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7193, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x719B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x719F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71C3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71D2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71D4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71D5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71D6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x71DE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7244, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7245, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7247, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7248, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x724A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x724B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x724C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x724D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x724E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x724F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7280, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7283, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7284, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x728B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x728C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7291, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7293, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x7297, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0, 0, 0}
        {0x8086, 0x29d2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x8086, 0x2a12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x8086, 0x2a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0, 0, 0}
-
index 12dfea89c7f37bdba45cda2d6a35cac2869a7016..d9b560fe9bbe68b0543091273cdacc7e5d87b2af 100644 (file)
@@ -236,11 +236,11 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
                        type = "??";
                else
                        type = types[map->type];
-               DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08x ",
+               DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
                               i,
                               map->offset,
                               map->size, type, map->flags,
-                              r_list->user_token);
+                              (unsigned long) r_list->user_token);
                if (map->mtrr < 0) {
                        DRM_PROC_PRINT("none\n");
                } else {
index e040f47f369f94255c9e0e4bd843be71b9184e22..480037331e4e39968c0609c0d91a27a6fd4c922c 100644 (file)
@@ -45,7 +45,7 @@
 #endif
 
 /** Maximum number of drawables in the SAREA */
-#define SAREA_MAX_DRAWABLES            256
+#define SAREA_MAX_DRAWABLES            256
 
 #define SAREA_DRAWABLE_CLAIMED_ENTRY    0x80000000
 
index eb7fa437355e4068a52d48d2f7e7afbdad9e2f00..26d8f675ed5df8e785900b7fb9e8f09c0e7aff17 100644 (file)
@@ -67,7 +67,7 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
        struct drm_sg_mem *entry;
        unsigned long pages, i, j;
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        if (!drm_core_check_feature(dev, DRIVER_SG))
                return -EINVAL;
@@ -81,7 +81,7 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
 
        memset(entry, 0, sizeof(*entry));
        pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
-       DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
+       DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages);
 
        entry->pages = pages;
        entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist),
@@ -122,8 +122,8 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
 
        entry->handle = ScatterHandle((unsigned long)entry->virtual);
 
-       DRM_DEBUG("sg alloc handle  = %08lx\n", entry->handle);
-       DRM_DEBUG("sg alloc virtual = %p\n", entry->virtual);
+       DRM_DEBUG("handle  = %08lx\n", entry->handle);
+       DRM_DEBUG("virtual = %p\n", entry->virtual);
 
        for (i = (unsigned long)entry->virtual, j = 0; j < pages;
             i += PAGE_SIZE, j++) {
@@ -210,7 +210,7 @@ int drm_sg_free(struct drm_device *dev, void *data,
        if (!entry || entry->handle != request->handle)
                return -EINVAL;
 
-       DRM_DEBUG("sg free virtual  = %p\n", entry->virtual);
+       DRM_DEBUG("virtual  = %p\n", entry->virtual);
 
        drm_sg_cleanup(entry);
 
index ee83ff9efed68026e189d4552bc59087f9908468..d93a217f856a7303d185396ea2a376e8cc3c3e65 100644 (file)
@@ -98,10 +98,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
 
        dev->driver = driver;
 
-       if (dev->driver->load)
-               if ((retcode = dev->driver->load(dev, ent->driver_data)))
-                       goto error_out_unreg;
-
        if (drm_core_has_AGP(dev)) {
                if (drm_device_is_agp(dev))
                        dev->agp = drm_agp_init(dev);
@@ -120,6 +116,10 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
                }
        }
 
+       if (dev->driver->load)
+               if ((retcode = dev->driver->load(dev, ent->driver_data)))
+                       goto error_out_unreg;
+
        retcode = drm_ctxbitmap_init(dev);
        if (retcode) {
                DRM_ERROR("Cannot allocate memory for context bitmap.\n");
@@ -168,11 +168,10 @@ static int drm_get_head(struct drm_device * dev, struct drm_head * head)
                                goto err_g1;
                        }
 
-                       head->dev_class = drm_sysfs_device_add(drm_class, head);
-                       if (IS_ERR(head->dev_class)) {
+                       ret = drm_sysfs_device_add(dev, head);
+                       if (ret) {
                                printk(KERN_ERR
                                       "DRM: Error sysfs_device_add.\n");
-                               ret = PTR_ERR(head->dev_class);
                                goto err_g2;
                        }
                        *heads = head;
@@ -218,13 +217,14 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
        if (ret)
                goto err_g1;
 
+       pci_set_master(pdev);
        if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
                printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
                goto err_g2;
        }
        if ((ret = drm_get_head(dev, &dev->primary)))
                goto err_g2;
-       
+
        DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
                 driver->name, driver->major, driver->minor, driver->patchlevel,
                 driver->date, dev->primary.minor);
@@ -283,7 +283,7 @@ int drm_put_head(struct drm_head * head)
        DRM_DEBUG("release secondary minor %d\n", minor);
 
        drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
-       drm_sysfs_device_remove(head->dev_class);
+       drm_sysfs_device_remove(head->dev);
 
        *head = (struct drm_head) {.dev = NULL};
 
index cf4349b00b07474f21fb6168a6bed2fa1a10a8a3..fa36153619e83a28696b1360de42c1776c943aec 100644 (file)
 #include "drm_core.h"
 #include "drmP.h"
 
+#define to_drm_device(d) container_of(d, struct drm_device, dev)
+
+/**
+ * drm_sysfs_suspend - DRM class suspend hook
+ * @dev: Linux device to suspend
+ * @state: power state to enter
+ *
+ * Just figures out what the actual struct drm_device associated with
+ * @dev is and calls its suspend hook, if present.
+ */
+static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
+{
+       struct drm_device *drm_dev = to_drm_device(dev);
+
+       printk(KERN_ERR "%s\n", __FUNCTION__);
+
+       if (drm_dev->driver->suspend)
+               return drm_dev->driver->suspend(drm_dev);
+
+       return 0;
+}
+
+/**
+ * drm_sysfs_resume - DRM class resume hook
+ * @dev: Linux device to resume
+ *
+ * Just figures out what the actual struct drm_device associated with
+ * @dev is and calls its resume hook, if present.
+ */
+static int drm_sysfs_resume(struct device *dev)
+{
+       struct drm_device *drm_dev = to_drm_device(dev);
+
+       if (drm_dev->driver->resume)
+               return drm_dev->driver->resume(drm_dev);
+
+       return 0;
+}
+
 /* Display the version of drm_core. This doesn't work right in current design */
 static ssize_t version_show(struct class *dev, char *buf)
 {
@@ -33,7 +72,7 @@ static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
  * @owner: pointer to the module that is to "own" this struct drm_sysfs_class
  * @name: pointer to a string for the name of this class.
  *
- * This is used to create a struct drm_sysfs_class pointer that can then be used
+ * This is used to create DRM class pointer that can then be used
  * in calls to drm_sysfs_device_add().
  *
  * Note, the pointer created here is to be destroyed when finished by making a
@@ -50,6 +89,9 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
                goto err_out;
        }
 
+       class->suspend = drm_sysfs_suspend;
+       class->resume = drm_sysfs_resume;
+
        err = class_create_file(class, &class_attr_version);
        if (err)
                goto err_out_class;
@@ -63,94 +105,100 @@ err_out:
 }
 
 /**
- * drm_sysfs_destroy - destroys a struct drm_sysfs_class structure
- * @cs: pointer to the struct drm_sysfs_class that is to be destroyed
+ * drm_sysfs_destroy - destroys DRM class
  *
- * Note, the pointer to be destroyed must have been created with a call to
- * drm_sysfs_create().
+ * Destroy the DRM device class.
  */
-void drm_sysfs_destroy(struct class *class)
+void drm_sysfs_destroy(void)
 {
-       if ((class == NULL) || (IS_ERR(class)))
+       if ((drm_class == NULL) || (IS_ERR(drm_class)))
                return;
-
-       class_remove_file(class, &class_attr_version);
-       class_destroy(class);
+       class_remove_file(drm_class, &class_attr_version);
+       class_destroy(drm_class);
 }
 
-static ssize_t show_dri(struct class_device *class_device, char *buf)
+static ssize_t show_dri(struct device *device, struct device_attribute *attr,
+                       char *buf)
 {
-       struct drm_device * dev = ((struct drm_head *)class_get_devdata(class_device))->dev;
+       struct drm_device *dev = to_drm_device(device);
        if (dev->driver->dri_library_name)
                return dev->driver->dri_library_name(dev, buf);
        return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name);
 }
 
-static struct class_device_attribute class_device_attrs[] = {
+static struct device_attribute device_attrs[] = {
        __ATTR(dri_library_name, S_IRUGO, show_dri, NULL),
 };
 
+/**
+ * drm_sysfs_device_release - do nothing
+ * @dev: Linux device
+ *
+ * Normally, this would free the DRM device associated with @dev, along
+ * with cleaning up any other stuff.  But we do that in the DRM core, so
+ * this function can just return and hope that the core does its job.
+ */
+static void drm_sysfs_device_release(struct device *dev)
+{
+       return;
+}
+
 /**
  * drm_sysfs_device_add - adds a class device to sysfs for a character driver
- * @cs: pointer to the struct class that this device should be registered to.
- * @dev: the dev_t for the device to be added.
- * @device: a pointer to a struct device that is assiociated with this class device.
- * @fmt: string for the class device's name
+ * @dev: DRM device to be added
+ * @head: DRM head in question
  *
- * A struct class_device will be created in sysfs, registered to the specified
- * class.  A "dev" file will be created, showing the dev_t for the device.  The
- * pointer to the struct class_device will be returned from the call.  Any further
- * sysfs files that might be required can be created using this pointer.
- * Note: the struct class passed to this function must have previously been
- * created with a call to drm_sysfs_create().
+ * Add a DRM device to the DRM's device model class.  We use @dev's PCI device
+ * as the parent for the Linux device, and make sure it has a file containing
+ * the driver we're using (for userspace compatibility).
  */
-struct class_device *drm_sysfs_device_add(struct class *cs, struct drm_head *head)
+int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head)
 {
-       struct class_device *class_dev;
-       int i, j, err;
-
-       class_dev = class_device_create(cs, NULL,
-                                       MKDEV(DRM_MAJOR, head->minor),
-                                       &(head->dev->pdev)->dev,
-                                       "card%d", head->minor);
-       if (IS_ERR(class_dev)) {
-               err = PTR_ERR(class_dev);
+       int err;
+       int i, j;
+
+       dev->dev.parent = &dev->pdev->dev;
+       dev->dev.class = drm_class;
+       dev->dev.release = drm_sysfs_device_release;
+       dev->dev.devt = head->device;
+       snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor);
+
+       err = device_register(&dev->dev);
+       if (err) {
+               DRM_ERROR("device add failed: %d\n", err);
                goto err_out;
        }
 
-       class_set_devdata(class_dev, head);
-
-       for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
-               err = class_device_create_file(class_dev,
-                                              &class_device_attrs[i]);
+       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+               err = device_create_file(&dev->dev, &device_attrs[i]);
                if (err)
                        goto err_out_files;
        }
 
-       return class_dev;
+       return 0;
 
 err_out_files:
        if (i > 0)
                for (j = 0; j < i; j++)
-                       class_device_remove_file(class_dev,
-                                                &class_device_attrs[i]);
-       class_device_unregister(class_dev);
+                       device_remove_file(&dev->dev, &device_attrs[i]);
+       device_unregister(&dev->dev);
 err_out:
-       return ERR_PTR(err);
+
+       return err;
 }
 
 /**
- * drm_sysfs_device_remove - removes a class device that was created with drm_sysfs_device_add()
- * @dev: the dev_t of the device that was previously registered.
+ * drm_sysfs_device_remove - remove DRM device
+ * @dev: DRM device to remove
  *
  * This call unregisters and cleans up a class device that was created with a
  * call to drm_sysfs_device_add()
  */
-void drm_sysfs_device_remove(struct class_device *class_dev)
+void drm_sysfs_device_remove(struct drm_device *dev)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
-               class_device_remove_file(class_dev, &class_device_attrs[i]);
-       class_device_unregister(class_dev);
+       for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
+               device_remove_file(&dev->dev, &device_attrs[i]);
+       device_unregister(&dev->dev);
 }
index ef5e6b130c4845aa8b3ad68b36538b34d90e6311..cea4105374b2b8c284b1fa05bd7772cd40bbf9d4 100644 (file)
@@ -180,7 +180,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
                return NOPAGE_SIGBUS;
        get_page(page);
 
-       DRM_DEBUG("shm_nopage 0x%lx\n", address);
+       DRM_DEBUG("0x%lx\n", address);
        return page;
 }
 
@@ -294,7 +294,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
 
        get_page(page);
 
-       DRM_DEBUG("dma_nopage 0x%lx (page %lu)\n", address, page_nr);
+       DRM_DEBUG("0x%lx (page %lu)\n", address, page_nr);
        return page;
 }
 
index eb381a7c5beed40920fa577061ebec084331da86..8d7ea81c4b66b3f70b242b02d2778f3c6052a9fc 100644 (file)
@@ -40,7 +40,7 @@
 
 #define I810_BUF_FREE          2
 #define I810_BUF_CLIENT                1
-#define I810_BUF_HARDWARE              0
+#define I810_BUF_HARDWARE      0
 
 #define I810_BUF_UNMAPPED 0
 #define I810_BUF_MAPPED   1
@@ -570,7 +570,7 @@ static void i810EmitState(struct drm_device * dev)
        drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
        unsigned int dirty = sarea_priv->dirty;
 
-       DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
+       DRM_DEBUG("%x\n", dirty);
 
        if (dirty & I810_UPLOAD_BUFFERS) {
                i810EmitDestVerified(dev, sarea_priv->BufferState);
@@ -802,8 +802,7 @@ static void i810_dma_dispatch_flip(struct drm_device * dev)
        int pitch = dev_priv->pitch;
        RING_LOCALS;
 
-       DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
-                 __FUNCTION__,
+       DRM_DEBUG("page=%d pfCurrentPage=%d\n",
                  dev_priv->current_page,
                  dev_priv->sarea_priv->pf_current_page);
 
@@ -848,8 +847,6 @@ static void i810_dma_quiescent(struct drm_device * dev)
        drm_i810_private_t *dev_priv = dev->dev_private;
        RING_LOCALS;
 
-/*     printk("%s\n", __FUNCTION__); */
-
        i810_kernel_lost_context(dev);
 
        BEGIN_LP_RING(4);
@@ -869,8 +866,6 @@ static int i810_flush_queue(struct drm_device * dev)
        int i, ret = 0;
        RING_LOCALS;
 
-/*     printk("%s\n", __FUNCTION__); */
-
        i810_kernel_lost_context(dev);
 
        BEGIN_LP_RING(2);
@@ -949,7 +944,7 @@ static int i810_dma_vertex(struct drm_device *dev, void *data,
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
+       DRM_DEBUG("idx %d used %d discard %d\n",
                  vertex->idx, vertex->used, vertex->discard);
 
        if (vertex->idx < 0 || vertex->idx > dma->buf_count)
@@ -987,7 +982,7 @@ static int i810_clear_bufs(struct drm_device *dev, void *data,
 static int i810_swap_bufs(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
 {
-       DRM_DEBUG("i810_swap_bufs\n");
+       DRM_DEBUG("\n");
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -1068,11 +1063,10 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf,
 
        sarea_priv->dirty = 0x7f;
 
-       DRM_DEBUG("dispatch mc addr 0x%lx, used 0x%x\n", address, used);
+       DRM_DEBUG("addr 0x%lx, used 0x%x\n", address, used);
 
        dev_priv->counter++;
        DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter);
-       DRM_DEBUG("i810_dma_dispatch_mc\n");
        DRM_DEBUG("start : %lx\n", start);
        DRM_DEBUG("used : %d\n", used);
        DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4);
@@ -1179,7 +1173,7 @@ static void i810_do_init_pageflip(struct drm_device * dev)
 {
        drm_i810_private_t *dev_priv = dev->dev_private;
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
        dev_priv->page_flipping = 1;
        dev_priv->current_page = 0;
        dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
@@ -1189,7 +1183,7 @@ static int i810_do_cleanup_pageflip(struct drm_device * dev)
 {
        drm_i810_private_t *dev_priv = dev->dev_private;
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
        if (dev_priv->current_page != 0)
                i810_dma_dispatch_flip(dev);
 
@@ -1202,7 +1196,7 @@ static int i810_flip_bufs(struct drm_device *dev, void *data,
 {
        drm_i810_private_t *dev_priv = dev->dev_private;
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
index 0af45872f67eef3756110faec83b467dd79ad790..0118849a567218632bc954e03c2c283a9d37e6a4 100644 (file)
@@ -25,7 +25,7 @@
  * DEALINGS IN THE SOFTWARE.
  *
  * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
- *         Jeff Hartmann <jhartmann@valinux.com>
+ *         Jeff Hartmann <jhartmann@valinux.com>
  *
  */
 
@@ -134,7 +134,7 @@ extern int i810_max_ioctl;
 #define I810_ADDR(reg)         (I810_BASE(reg) + reg)
 #define I810_DEREF(reg)                *(__volatile__ int *)I810_ADDR(reg)
 #define I810_READ(reg)         I810_DEREF(reg)
-#define I810_WRITE(reg,val)    do { I810_DEREF(reg) = val; } while (0)
+#define I810_WRITE(reg,val)    do { I810_DEREF(reg) = val; } while (0)
 #define I810_DEREF16(reg)      *(__volatile__ u16 *)I810_ADDR(reg)
 #define I810_READ16(reg)       I810_DEREF16(reg)
 #define I810_WRITE16(reg,val)  do { I810_DEREF16(reg) = val; } while (0)
@@ -145,7 +145,7 @@ extern int i810_max_ioctl;
 
 #define BEGIN_LP_RING(n) do {                                          \
        if (I810_VERBOSE)                                               \
-           DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__);    \
+               DRM_DEBUG("BEGIN_LP_RING(%d)\n", n);                    \
        if (dev_priv->ring.space < n*4)                                 \
                i810_wait_ring(dev, n*4);                               \
        dev_priv->ring.space -= n*4;                                    \
@@ -155,19 +155,19 @@ extern int i810_max_ioctl;
 } while (0)
 
 #define ADVANCE_LP_RING() do {                                 \
-       if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n");       \
-       dev_priv->ring.tail = outring;                          \
+       if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n");       \
+       dev_priv->ring.tail = outring;                          \
        I810_WRITE(LP_RING + RING_TAIL, outring);               \
 } while(0)
 
-#define OUT_RING(n) do {                                               \
+#define OUT_RING(n) do {                                               \
        if (I810_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));      \
        *(volatile unsigned int *)(virt + outring) = n;                 \
        outring += 4;                                                   \
        outring &= ringmask;                                            \
 } while (0)
 
-#define GFX_OP_USER_INTERRUPT          ((0<<29)|(2<<23))
+#define GFX_OP_USER_INTERRUPT          ((0<<29)|(2<<23))
 #define GFX_OP_BREAKPOINT_INTERRUPT    ((0<<29)|(1<<23))
 #define CMD_REPORT_HEAD                        (7<<23)
 #define CMD_STORE_DWORD_IDX            ((0x21<<23) | 0x1)
@@ -184,28 +184,28 @@ extern int i810_max_ioctl;
 
 #define I810REG_HWSTAM         0x02098
 #define I810REG_INT_IDENTITY_R 0x020a4
-#define I810REG_INT_MASK_R     0x020a8
+#define I810REG_INT_MASK_R     0x020a8
 #define I810REG_INT_ENABLE_R   0x020a0
 
-#define LP_RING                0x2030
-#define HP_RING                0x2040
-#define RING_TAIL                      0x00
+#define LP_RING                        0x2030
+#define HP_RING                        0x2040
+#define RING_TAIL              0x00
 #define TAIL_ADDR              0x000FFFF8
-#define RING_HEAD                      0x04
-#define HEAD_WRAP_COUNT        0xFFE00000
-#define HEAD_WRAP_ONE          0x00200000
-#define HEAD_ADDR              0x001FFFFC
-#define RING_START                     0x08
-#define START_ADDR             0x00FFFFF8
-#define RING_LEN                       0x0C
-#define RING_NR_PAGES          0x000FF000
-#define RING_REPORT_MASK       0x00000006
-#define RING_REPORT_64K        0x00000002
-#define RING_REPORT_128K       0x00000004
-#define RING_NO_REPORT         0x00000000
-#define RING_VALID_MASK        0x00000001
-#define RING_VALID             0x00000001
-#define RING_INVALID           0x00000000
+#define RING_HEAD              0x04
+#define HEAD_WRAP_COUNT                0xFFE00000
+#define HEAD_WRAP_ONE          0x00200000
+#define HEAD_ADDR              0x001FFFFC
+#define RING_START             0x08
+#define START_ADDR             0x00FFFFF8
+#define RING_LEN               0x0C
+#define RING_NR_PAGES          0x000FF000
+#define RING_REPORT_MASK       0x00000006
+#define RING_REPORT_64K                0x00000002
+#define RING_REPORT_128K       0x00000004
+#define RING_NO_REPORT         0x00000000
+#define RING_VALID_MASK                0x00000001
+#define RING_VALID             0x00000001
+#define RING_INVALID           0x00000000
 
 #define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
 #define SC_UPDATE_SCISSOR       (0x1<<1)
index 69a363edb0d202b157d262ea0150aa185384eb1a..379cbdad492125752f51f96919cb44f38c1193a9 100644 (file)
@@ -42,7 +42,7 @@
 
 #define I830_BUF_FREE          2
 #define I830_BUF_CLIENT                1
-#define I830_BUF_HARDWARE              0
+#define I830_BUF_HARDWARE      0
 
 #define I830_BUF_UNMAPPED 0
 #define I830_BUF_MAPPED   1
index 968a6d9f9dcb63974a2df703d546bb9152da6813..4b00d2dd4f684f7dfde4256c84f09bf08844e2b6 100644 (file)
@@ -12,9 +12,9 @@
 #define _I830_DEFINES_
 
 #define I830_DMA_BUF_ORDER             12
-#define I830_DMA_BUF_SZ                (1<<I830_DMA_BUF_ORDER)
-#define I830_DMA_BUF_NR                256
-#define I830_NR_SAREA_CLIPRECTS        8
+#define I830_DMA_BUF_SZ                        (1<<I830_DMA_BUF_ORDER)
+#define I830_DMA_BUF_NR                        256
+#define I830_NR_SAREA_CLIPRECTS                8
 
 /* Each region is a minimum of 64k, and there are at most 64 of them.
  */
@@ -58,7 +58,7 @@
 #define I830_UPLOAD_TEXBLEND_MASK      0xf00000
 #define I830_UPLOAD_TEX_PALETTE_N(n)    (0x1000000 << (n))
 #define I830_UPLOAD_TEX_PALETTE_SHARED 0x4000000
-#define I830_UPLOAD_STIPPLE            0x8000000
+#define I830_UPLOAD_STIPPLE            0x8000000
 
 /* Indices into buf.Setup where various bits of state are mirrored per
  * context and per buffer.  These can be fired at the card as a unit,
index db3a9fa83960ec22ebc3f288606e02cdddbcf1b6..4caba8c54455582271385d3bc69ebf61b93ed632 100644 (file)
@@ -25,7 +25,7 @@
  * DEALINGS IN THE SOFTWARE.
  *
  * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
- *         Jeff Hartmann <jhartmann@valinux.com>
+ *         Jeff Hartmann <jhartmann@valinux.com>
  *
  */
 
@@ -156,8 +156,7 @@ extern int i830_driver_device_is_agp(struct drm_device * dev);
 
 #define BEGIN_LP_RING(n) do {                          \
        if (I830_VERBOSE)                               \
-               printk("BEGIN_LP_RING(%d) in %s\n",     \
-                         n, __FUNCTION__);             \
+               printk("BEGIN_LP_RING(%d)\n", (n));     \
        if (dev_priv->ring.space < n*4)                 \
                i830_wait_ring(dev, n*4, __FUNCTION__);         \
        outcount = 0;                                   \
@@ -183,7 +182,7 @@ extern int i830_driver_device_is_agp(struct drm_device * dev);
 
 extern int i830_wait_ring(struct drm_device * dev, int n, const char *caller);
 
-#define GFX_OP_USER_INTERRUPT          ((0<<29)|(2<<23))
+#define GFX_OP_USER_INTERRUPT          ((0<<29)|(2<<23))
 #define GFX_OP_BREAKPOINT_INTERRUPT    ((0<<29)|(1<<23))
 #define CMD_REPORT_HEAD                        (7<<23)
 #define CMD_STORE_DWORD_IDX            ((0x21<<23) | 0x1)
@@ -203,30 +202,30 @@ extern int i830_wait_ring(struct drm_device * dev, int n, const char *caller);
 
 #define I830REG_HWSTAM         0x02098
 #define I830REG_INT_IDENTITY_R 0x020a4
-#define I830REG_INT_MASK_R     0x020a8
+#define I830REG_INT_MASK_R     0x020a8
 #define I830REG_INT_ENABLE_R   0x020a0
 
 #define I830_IRQ_RESERVED ((1<<13)|(3<<2))
 
-#define LP_RING                0x2030
-#define HP_RING                0x2040
-#define RING_TAIL                      0x00
+#define LP_RING                        0x2030
+#define HP_RING                        0x2040
+#define RING_TAIL              0x00
 #define TAIL_ADDR              0x001FFFF8
-#define RING_HEAD                      0x04
-#define HEAD_WRAP_COUNT        0xFFE00000
-#define HEAD_WRAP_ONE          0x00200000
-#define HEAD_ADDR              0x001FFFFC
-#define RING_START                     0x08
-#define START_ADDR             0x0xFFFFF000
-#define RING_LEN                       0x0C
-#define RING_NR_PAGES          0x001FF000
-#define RING_REPORT_MASK       0x00000006
-#define RING_REPORT_64K        0x00000002
-#define RING_REPORT_128K       0x00000004
-#define RING_NO_REPORT         0x00000000
-#define RING_VALID_MASK        0x00000001
-#define RING_VALID             0x00000001
-#define RING_INVALID           0x00000000
+#define RING_HEAD              0x04
+#define HEAD_WRAP_COUNT                0xFFE00000
+#define HEAD_WRAP_ONE          0x00200000
+#define HEAD_ADDR              0x001FFFFC
+#define RING_START             0x08
+#define START_ADDR             0x0xFFFFF000
+#define RING_LEN               0x0C
+#define RING_NR_PAGES          0x001FF000
+#define RING_REPORT_MASK       0x00000006
+#define RING_REPORT_64K                0x00000002
+#define RING_REPORT_128K       0x00000004
+#define RING_NO_REPORT         0x00000000
+#define RING_VALID_MASK                0x00000001
+#define RING_VALID             0x00000001
+#define RING_INVALID           0x00000000
 
 #define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
 #define SC_UPDATE_SCISSOR       (0x1<<1)
@@ -279,9 +278,9 @@ extern int i830_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define XY_SRC_COPY_BLT_WRITE_ALPHA     (1<<21)
 #define XY_SRC_COPY_BLT_WRITE_RGB       (1<<20)
 
-#define MI_BATCH_BUFFER        ((0x30<<23)|1)
-#define MI_BATCH_BUFFER_START  (0x31<<23)
-#define MI_BATCH_BUFFER_END    (0xA<<23)
+#define MI_BATCH_BUFFER                ((0x30<<23)|1)
+#define MI_BATCH_BUFFER_START  (0x31<<23)
+#define MI_BATCH_BUFFER_END    (0xA<<23)
 #define MI_BATCH_NON_SECURE    (1)
 
 #define MI_WAIT_FOR_EVENT       ((0x3<<23))
index 76403f4b62000a111d06913fabf6ea5d62ada826..a33db5f0967fbbb798706ec6c3125347371b6f10 100644 (file)
@@ -144,7 +144,7 @@ int i830_irq_wait(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
        drm_i830_private_t *dev_priv = dev->dev_private;
-       drm_i830_irq_wait_t *irqwait = data; 
+       drm_i830_irq_wait_t *irqwait = data;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
index e61a43e5b3ac1018ed93873576013578af49270d..43986d81ae34f4b26fd8b1c4f717f1ae0ea13c17 100644 (file)
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
-                      dev->pci_device == 0x2982 || \
-                      dev->pci_device == 0x2992 || \
-                      dev->pci_device == 0x29A2 || \
-                      dev->pci_device == 0x2A02 || \
-                      dev->pci_device == 0x2A12)
-
-#define IS_G33(dev) (dev->pci_device == 0x29b2 || \
-                    dev->pci_device == 0x29c2 || \
-                    dev->pci_device == 0x29d2)
-
 /* Really want an OS-independent resettable timer.  Would like to have
  * this loop run for (eg) 3 sec, but have the timer reset every time
  * the head pointer changes, so that EBUSY only happens if the ring
@@ -90,6 +79,7 @@ void i915_kernel_lost_context(struct drm_device * dev)
 
 static int i915_dma_cleanup(struct drm_device * dev)
 {
+       drm_i915_private_t *dev_priv = dev->dev_private;
        /* Make sure interrupts are disabled here because the uninstall ioctl
         * may not have been called from userspace and after dev_private
         * is freed, it's too late.
@@ -97,52 +87,42 @@ static int i915_dma_cleanup(struct drm_device * dev)
        if (dev->irq)
                drm_irq_uninstall(dev);
 
-       if (dev->dev_private) {
-               drm_i915_private_t *dev_priv =
-                   (drm_i915_private_t *) dev->dev_private;
-
-               if (dev_priv->ring.virtual_start) {
-                       drm_core_ioremapfree(&dev_priv->ring.map, dev);
-               }
-
-               if (dev_priv->status_page_dmah) {
-                       drm_pci_free(dev, dev_priv->status_page_dmah);
-                       /* Need to rewrite hardware status page */
-                       I915_WRITE(0x02080, 0x1ffff000);
-               }
-
-               if (dev_priv->status_gfx_addr) {
-                       dev_priv->status_gfx_addr = 0;
-                       drm_core_ioremapfree(&dev_priv->hws_map, dev);
-                       I915_WRITE(0x2080, 0x1ffff000);
-               }
+       if (dev_priv->ring.virtual_start) {
+               drm_core_ioremapfree(&dev_priv->ring.map, dev);
+               dev_priv->ring.virtual_start = 0;
+               dev_priv->ring.map.handle = 0;
+               dev_priv->ring.map.size = 0;
+       }
 
-               drm_free(dev->dev_private, sizeof(drm_i915_private_t),
-                        DRM_MEM_DRIVER);
+       if (dev_priv->status_page_dmah) {
+               drm_pci_free(dev, dev_priv->status_page_dmah);
+               dev_priv->status_page_dmah = NULL;
+               /* Need to rewrite hardware status page */
+               I915_WRITE(0x02080, 0x1ffff000);
+       }
 
-               dev->dev_private = NULL;
+       if (dev_priv->status_gfx_addr) {
+               dev_priv->status_gfx_addr = 0;
+               drm_core_ioremapfree(&dev_priv->hws_map, dev);
+               I915_WRITE(0x2080, 0x1ffff000);
        }
 
        return 0;
 }
 
-static int i915_initialize(struct drm_device * dev,
-                          drm_i915_private_t * dev_priv,
-                          drm_i915_init_t * init)
+static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
 {
-       memset(dev_priv, 0, sizeof(drm_i915_private_t));
+       drm_i915_private_t *dev_priv = dev->dev_private;
 
        dev_priv->sarea = drm_getsarea(dev);
        if (!dev_priv->sarea) {
                DRM_ERROR("can not find sarea!\n");
-               dev->dev_private = (void *)dev_priv;
                i915_dma_cleanup(dev);
                return -EINVAL;
        }
 
        dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
        if (!dev_priv->mmio_map) {
-               dev->dev_private = (void *)dev_priv;
                i915_dma_cleanup(dev);
                DRM_ERROR("can not find mmio map!\n");
                return -EINVAL;
@@ -165,7 +145,6 @@ static int i915_initialize(struct drm_device * dev,
        drm_core_ioremap(&dev_priv->ring.map, dev);
 
        if (dev_priv->ring.map.handle == NULL) {
-               dev->dev_private = (void *)dev_priv;
                i915_dma_cleanup(dev);
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
@@ -197,7 +176,6 @@ static int i915_initialize(struct drm_device * dev,
                        drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
 
                if (!dev_priv->status_page_dmah) {
-                       dev->dev_private = (void *)dev_priv;
                        i915_dma_cleanup(dev);
                        DRM_ERROR("Can not allocate hardware status page\n");
                        return -ENOMEM;
@@ -209,7 +187,6 @@ static int i915_initialize(struct drm_device * dev,
                I915_WRITE(0x02080, dev_priv->dma_status_page);
        }
        DRM_DEBUG("Enabled hardware status page\n");
-       dev->dev_private = (void *)dev_priv;
        return 0;
 }
 
@@ -254,17 +231,12 @@ static int i915_dma_resume(struct drm_device * dev)
 static int i915_dma_init(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv;
        drm_i915_init_t *init = data;
        int retcode = 0;
 
        switch (init->func) {
        case I915_INIT_DMA:
-               dev_priv = drm_alloc(sizeof(drm_i915_private_t),
-                                    DRM_MEM_DRIVER);
-               if (dev_priv == NULL)
-                       return -ENOMEM;
-               retcode = i915_initialize(dev, dev_priv, init);
+               retcode = i915_initialize(dev, init);
                break;
        case I915_CLEANUP_DMA:
                retcode = i915_dma_cleanup(dev);
@@ -351,7 +323,7 @@ static int validate_cmd(int cmd)
 {
        int ret = do_validate_cmd(cmd);
 
-/*     printk("validate_cmd( %x ): %d\n", cmd, ret); */
+/*     printk("validate_cmd( %x ): %d\n", cmd, ret); */
 
        return ret;
 }
@@ -685,7 +657,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
        int value;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -719,7 +691,7 @@ static int i915_setparam(struct drm_device *dev, void *data,
        drm_i915_setparam_t *param = data;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -749,7 +721,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
        drm_i915_hws_addr_t *hws = data;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -757,7 +729,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
 
        dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
 
-       dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws->addr;
+       dev_priv->hws_map.offset = dev->agp->base + hws->addr;
        dev_priv->hws_map.size = 4*1024;
        dev_priv->hws_map.type = 0;
        dev_priv->hws_map.flags = 0;
@@ -765,7 +737,6 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
 
        drm_core_ioremap(&dev_priv->hws_map, dev);
        if (dev_priv->hws_map.handle == NULL) {
-               dev->dev_private = (void *)dev_priv;
                i915_dma_cleanup(dev);
                dev_priv->status_gfx_addr = 0;
                DRM_ERROR("can not ioremap virtual address for"
@@ -784,6 +755,10 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
 
 int i915_driver_load(struct drm_device *dev, unsigned long flags)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long base, size;
+       int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
+
        /* i915 has 4 more counters */
        dev->counters += 4;
        dev->types[6] = _DRM_STAT_IRQ;
@@ -791,24 +766,51 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev->types[8] = _DRM_STAT_SECONDARY;
        dev->types[9] = _DRM_STAT_DMA;
 
+       dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER);
+       if (dev_priv == NULL)
+               return -ENOMEM;
+
+       memset(dev_priv, 0, sizeof(drm_i915_private_t));
+
+       dev->dev_private = (void *)dev_priv;
+
+       /* Add register map (needed for suspend/resume) */
+       base = drm_get_resource_start(dev, mmio_bar);
+       size = drm_get_resource_len(dev, mmio_bar);
+
+       ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
+                        _DRM_KERNEL | _DRM_DRIVER,
+                        &dev_priv->mmio_map);
+       return ret;
+}
+
+int i915_driver_unload(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->mmio_map)
+               drm_rmmap(dev, dev_priv->mmio_map);
+
+       drm_free(dev->dev_private, sizeof(drm_i915_private_t),
+                DRM_MEM_DRIVER);
+
        return 0;
 }
 
 void i915_driver_lastclose(struct drm_device * dev)
 {
-       if (dev->dev_private) {
-               drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       if (dev_priv->agp_heap)
                i915_mem_takedown(&(dev_priv->agp_heap));
-       }
+
        i915_dma_cleanup(dev);
 }
 
 void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
 {
-       if (dev->dev_private) {
-               drm_i915_private_t *dev_priv = dev->dev_private;
-               i915_mem_release(dev, file_priv, dev_priv->agp_heap);
-       }
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       i915_mem_release(dev, file_priv, dev_priv->agp_heap);
 }
 
 struct drm_ioctl_desc i915_ioctls[] = {
index 85bcc276f8043ed5f8a01dec203c1dc16cc6af59..52e51033d32c47d21bf487fccb86205c15620837 100644 (file)
@@ -38,6 +38,465 @@ static struct pci_device_id pciidlist[] = {
        i915_PCI_IDS
 };
 
+enum pipe {
+    PIPE_A = 0,
+    PIPE_B,
+};
+
+static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (pipe == PIPE_A)
+               return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE);
+       else
+               return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE);
+}
+
+static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+       u32 *array;
+       int i;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return;
+
+       if (pipe == PIPE_A)
+               array = dev_priv->save_palette_a;
+       else
+               array = dev_priv->save_palette_b;
+
+       for(i = 0; i < 256; i++)
+               array[i] = I915_READ(reg + (i << 2));
+}
+
+static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+       u32 *array;
+       int i;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return;
+
+       if (pipe == PIPE_A)
+               array = dev_priv->save_palette_a;
+       else
+               array = dev_priv->save_palette_b;
+
+       for(i = 0; i < 256; i++)
+               I915_WRITE(reg + (i << 2), array[i]);
+}
+
+static u8 i915_read_indexed(u16 index_port, u16 data_port, u8 reg)
+{
+       outb(reg, index_port);
+       return inb(data_port);
+}
+
+static u8 i915_read_ar(u16 st01, u8 reg, u16 palette_enable)
+{
+       inb(st01);
+       outb(palette_enable | reg, VGA_AR_INDEX);
+       return inb(VGA_AR_DATA_READ);
+}
+
+static void i915_write_ar(u8 st01, u8 reg, u8 val, u16 palette_enable)
+{
+       inb(st01);
+       outb(palette_enable | reg, VGA_AR_INDEX);
+       outb(val, VGA_AR_DATA_WRITE);
+}
+
+static void i915_write_indexed(u16 index_port, u16 data_port, u8 reg, u8 val)
+{
+       outb(reg, index_port);
+       outb(val, data_port);
+}
+
+static void i915_save_vga(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+       u16 cr_index, cr_data, st01;
+
+       /* VGA color palette registers */
+       dev_priv->saveDACMASK = inb(VGA_DACMASK);
+       /* DACCRX automatically increments during read */
+       outb(0, VGA_DACRX);
+       /* Read 3 bytes of color data from each index */
+       for (i = 0; i < 256 * 3; i++)
+               dev_priv->saveDACDATA[i] = inb(VGA_DACDATA);
+
+       /* MSR bits */
+       dev_priv->saveMSR = inb(VGA_MSR_READ);
+       if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
+               cr_index = VGA_CR_INDEX_CGA;
+               cr_data = VGA_CR_DATA_CGA;
+               st01 = VGA_ST01_CGA;
+       } else {
+               cr_index = VGA_CR_INDEX_MDA;
+               cr_data = VGA_CR_DATA_MDA;
+               st01 = VGA_ST01_MDA;
+       }
+
+       /* CRT controller regs */
+       i915_write_indexed(cr_index, cr_data, 0x11,
+                          i915_read_indexed(cr_index, cr_data, 0x11) &
+                          (~0x80));
+       for (i = 0; i < 0x24; i++)
+               dev_priv->saveCR[i] =
+                       i915_read_indexed(cr_index, cr_data, i);
+       /* Make sure we don't turn off CR group 0 writes */
+       dev_priv->saveCR[0x11] &= ~0x80;
+
+       /* Attribute controller registers */
+       inb(st01);
+       dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX);
+       for (i = 0; i < 20; i++)
+               dev_priv->saveAR[i] = i915_read_ar(st01, i, 0);
+       inb(st01);
+       outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX);
+
+       /* Graphics controller registers */
+       for (i = 0; i < 9; i++)
+               dev_priv->saveGR[i] =
+                       i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, i);
+
+       dev_priv->saveGR[0x10] =
+               i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10);
+       dev_priv->saveGR[0x11] =
+               i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11);
+       dev_priv->saveGR[0x18] =
+               i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18);
+
+       /* Sequencer registers */
+       for (i = 0; i < 8; i++)
+               dev_priv->saveSR[i] =
+                       i915_read_indexed(VGA_SR_INDEX, VGA_SR_DATA, i);
+}
+
+static void i915_restore_vga(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+       u16 cr_index, cr_data, st01;
+
+       /* MSR bits */
+       outb(dev_priv->saveMSR, VGA_MSR_WRITE);
+       if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
+               cr_index = VGA_CR_INDEX_CGA;
+               cr_data = VGA_CR_DATA_CGA;
+               st01 = VGA_ST01_CGA;
+       } else {
+               cr_index = VGA_CR_INDEX_MDA;
+               cr_data = VGA_CR_DATA_MDA;
+               st01 = VGA_ST01_MDA;
+       }
+
+       /* Sequencer registers, don't write SR07 */
+       for (i = 0; i < 7; i++)
+               i915_write_indexed(VGA_SR_INDEX, VGA_SR_DATA, i,
+                                  dev_priv->saveSR[i]);
+
+       /* CRT controller regs */
+       /* Enable CR group 0 writes */
+       i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]);
+       for (i = 0; i < 0x24; i++)
+               i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]);
+
+       /* Graphics controller regs */
+       for (i = 0; i < 9; i++)
+               i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, i,
+                                  dev_priv->saveGR[i]);
+
+       i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10,
+                          dev_priv->saveGR[0x10]);
+       i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11,
+                          dev_priv->saveGR[0x11]);
+       i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18,
+                          dev_priv->saveGR[0x18]);
+
+       /* Attribute controller registers */
+       for (i = 0; i < 20; i++)
+               i915_write_ar(st01, i, dev_priv->saveAR[i], 0);
+       inb(st01); /* switch back to index mode */
+       outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX);
+
+       /* VGA color palette registers */
+       outb(dev_priv->saveDACMASK, VGA_DACMASK);
+       /* DACCRX automatically increments during read */
+       outb(0, VGA_DACWX);
+       /* Read 3 bytes of color data from each index */
+       for (i = 0; i < 256 * 3; i++)
+               outb(dev_priv->saveDACDATA[i], VGA_DACDATA);
+
+}
+
+static int i915_suspend(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+
+       if (!dev || !dev_priv) {
+               printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv);
+               printk(KERN_ERR "DRM not initialized, aborting suspend.\n");
+               return -ENODEV;
+       }
+
+       pci_save_state(dev->pdev);
+       pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
+
+       /* Pipe & plane A info */
+       dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
+       dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
+       dev_priv->saveFPA0 = I915_READ(FPA0);
+       dev_priv->saveFPA1 = I915_READ(FPA1);
+       dev_priv->saveDPLL_A = I915_READ(DPLL_A);
+       if (IS_I965G(dev))
+               dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
+       dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
+       dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
+       dev_priv->saveHSYNC_A = I915_READ(HSYNC_A);
+       dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A);
+       dev_priv->saveVBLANK_A = I915_READ(VBLANK_A);
+       dev_priv->saveVSYNC_A = I915_READ(VSYNC_A);
+       dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
+
+       dev_priv->saveDSPACNTR = I915_READ(DSPACNTR);
+       dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE);
+       dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
+       dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
+       dev_priv->saveDSPABASE = I915_READ(DSPABASE);
+       if (IS_I965G(dev)) {
+               dev_priv->saveDSPASURF = I915_READ(DSPASURF);
+               dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
+       }
+       i915_save_palette(dev, PIPE_A);
+
+       /* Pipe & plane B info */
+       dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
+       dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC);
+       dev_priv->saveFPB0 = I915_READ(FPB0);
+       dev_priv->saveFPB1 = I915_READ(FPB1);
+       dev_priv->saveDPLL_B = I915_READ(DPLL_B);
+       if (IS_I965G(dev))
+               dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
+       dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
+       dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
+       dev_priv->saveHSYNC_B = I915_READ(HSYNC_B);
+       dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B);
+       dev_priv->saveVBLANK_B = I915_READ(VBLANK_B);
+       dev_priv->saveVSYNC_B = I915_READ(VSYNC_B);
+       dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
+
+       dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR);
+       dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE);
+       dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
+       dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
+       dev_priv->saveDSPBBASE = I915_READ(DSPBBASE);
+       if (IS_I965GM(dev) || IS_IGD_GM(dev)) {
+               dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
+               dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
+       }
+       i915_save_palette(dev, PIPE_B);
+
+       /* CRT state */
+       dev_priv->saveADPA = I915_READ(ADPA);
+
+       /* LVDS state */
+       dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
+       dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
+       dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+       if (IS_I965G(dev))
+               dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
+       if (IS_MOBILE(dev) && !IS_I830(dev))
+               dev_priv->saveLVDS = I915_READ(LVDS);
+       if (!IS_I830(dev) && !IS_845G(dev))
+               dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
+       dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON);
+       dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF);
+       dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE);
+
+       /* FIXME: save TV & SDVO state */
+
+       /* FBC state */
+       dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
+       dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
+       dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
+       dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
+
+       /* VGA state */
+       dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0);
+       dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1);
+       dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV);
+       dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
+
+       /* Scratch space */
+       for (i = 0; i < 16; i++) {
+               dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2));
+               dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
+       }
+       for (i = 0; i < 3; i++)
+               dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
+
+       i915_save_vga(dev);
+
+       /* Shut down the device */
+       pci_disable_device(dev->pdev);
+       pci_set_power_state(dev->pdev, PCI_D3hot);
+
+       return 0;
+}
+
+static int i915_resume(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+
+       pci_set_power_state(dev->pdev, PCI_D0);
+       pci_restore_state(dev->pdev);
+       if (pci_enable_device(dev->pdev))
+               return -1;
+
+       pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
+
+       /* Pipe & plane A info */
+       /* Prime the clock */
+       if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
+               I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
+                          ~DPLL_VCO_ENABLE);
+               udelay(150);
+       }
+       I915_WRITE(FPA0, dev_priv->saveFPA0);
+       I915_WRITE(FPA1, dev_priv->saveFPA1);
+       /* Actually enable it */
+       I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
+       udelay(150);
+       if (IS_I965G(dev))
+               I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
+       udelay(150);
+
+       /* Restore mode */
+       I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
+       I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
+       I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
+       I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
+       I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
+       I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
+       I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
+
+       /* Restore plane info */
+       I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
+       I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
+       I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
+       I915_WRITE(DSPABASE, dev_priv->saveDSPABASE);
+       I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
+       if (IS_I965G(dev)) {
+               I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
+               I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
+       }
+
+       if ((dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) &&
+           (dev_priv->saveDPLL_A & DPLL_VGA_MODE_DIS))
+               I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
+
+       i915_restore_palette(dev, PIPE_A);
+       /* Enable the plane */
+       I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
+       I915_WRITE(DSPABASE, I915_READ(DSPABASE));
+
+       /* Pipe & plane B info */
+       if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
+               I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
+                          ~DPLL_VCO_ENABLE);
+               udelay(150);
+       }
+       I915_WRITE(FPB0, dev_priv->saveFPB0);
+       I915_WRITE(FPB1, dev_priv->saveFPB1);
+       /* Actually enable it */
+       I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
+       udelay(150);
+       if (IS_I965G(dev))
+               I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
+       udelay(150);
+
+       /* Restore mode */
+       I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
+       I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
+       I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
+       I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
+       I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
+       I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
+       I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
+
+       /* Restore plane info */
+       I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
+       I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
+       I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
+       I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE);
+       I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
+       if (IS_I965G(dev)) {
+               I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
+               I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
+       }
+
+       if ((dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) &&
+           (dev_priv->saveDPLL_B & DPLL_VGA_MODE_DIS))
+               I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
+       i915_restore_palette(dev, PIPE_A);
+       /* Enable the plane */
+       I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
+       I915_WRITE(DSPBBASE, I915_READ(DSPBBASE));
+
+       /* CRT state */
+       I915_WRITE(ADPA, dev_priv->saveADPA);
+
+       /* LVDS state */
+       if (IS_I965G(dev))
+               I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
+       if (IS_MOBILE(dev) && !IS_I830(dev))
+               I915_WRITE(LVDS, dev_priv->saveLVDS);
+       if (!IS_I830(dev) && !IS_845G(dev))
+               I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
+
+       I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
+       I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
+       I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON);
+       I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF);
+       I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE);
+       I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
+
+       /* FIXME: restore TV & SDVO state */
+
+       /* FBC info */
+       I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
+       I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
+       I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
+       I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
+
+       /* VGA state */
+       I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
+       I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0);
+       I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1);
+       I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV);
+       udelay(150);
+
+       for (i = 0; i < 16; i++) {
+               I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]);
+               I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
+       }
+       for (i = 0; i < 3; i++)
+               I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
+
+       i915_restore_vga(dev);
+
+       return 0;
+}
+
 static struct drm_driver driver = {
        /* don't use mtrr's here, the Xserver or user space app should
         * deal with them for intel hardware.
@@ -47,8 +506,11 @@ static struct drm_driver driver = {
            DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
            DRIVER_IRQ_VBL2,
        .load = i915_driver_load,
+       .unload = i915_driver_unload,
        .lastclose = i915_driver_lastclose,
        .preclose = i915_driver_preclose,
+       .suspend = i915_suspend,
+       .resume = i915_resume,
        .device_is_agp = i915_driver_device_is_agp,
        .vblank_wait = i915_driver_vblank_wait,
        .vblank_wait2 = i915_driver_vblank_wait2,
@@ -77,7 +539,7 @@ static struct drm_driver driver = {
                 .name = DRIVER_NAME,
                 .id_table = pciidlist,
        },
-       
+
        .name = DRIVER_NAME,
        .desc = DRIVER_DESC,
        .date = DRIVER_DATE,
index e064292e703ac7a348f12421a3551e860b866497..37bbf6729b4e699fa5ef66eeadfba3fa2aac07e3 100644 (file)
@@ -114,6 +114,85 @@ typedef struct drm_i915_private {
        spinlock_t swaps_lock;
        drm_i915_vbl_swap_t vbl_swaps;
        unsigned int swaps_pending;
+
+       /* Register state */
+       u8 saveLBB;
+       u32 saveDSPACNTR;
+       u32 saveDSPBCNTR;
+       u32 savePIPEACONF;
+       u32 savePIPEBCONF;
+       u32 savePIPEASRC;
+       u32 savePIPEBSRC;
+       u32 saveFPA0;
+       u32 saveFPA1;
+       u32 saveDPLL_A;
+       u32 saveDPLL_A_MD;
+       u32 saveHTOTAL_A;
+       u32 saveHBLANK_A;
+       u32 saveHSYNC_A;
+       u32 saveVTOTAL_A;
+       u32 saveVBLANK_A;
+       u32 saveVSYNC_A;
+       u32 saveBCLRPAT_A;
+       u32 saveDSPASTRIDE;
+       u32 saveDSPASIZE;
+       u32 saveDSPAPOS;
+       u32 saveDSPABASE;
+       u32 saveDSPASURF;
+       u32 saveDSPATILEOFF;
+       u32 savePFIT_PGM_RATIOS;
+       u32 saveBLC_PWM_CTL;
+       u32 saveBLC_PWM_CTL2;
+       u32 saveFPB0;
+       u32 saveFPB1;
+       u32 saveDPLL_B;
+       u32 saveDPLL_B_MD;
+       u32 saveHTOTAL_B;
+       u32 saveHBLANK_B;
+       u32 saveHSYNC_B;
+       u32 saveVTOTAL_B;
+       u32 saveVBLANK_B;
+       u32 saveVSYNC_B;
+       u32 saveBCLRPAT_B;
+       u32 saveDSPBSTRIDE;
+       u32 saveDSPBSIZE;
+       u32 saveDSPBPOS;
+       u32 saveDSPBBASE;
+       u32 saveDSPBSURF;
+       u32 saveDSPBTILEOFF;
+       u32 saveVCLK_DIVISOR_VGA0;
+       u32 saveVCLK_DIVISOR_VGA1;
+       u32 saveVCLK_POST_DIV;
+       u32 saveVGACNTRL;
+       u32 saveADPA;
+       u32 saveLVDS;
+       u32 saveLVDSPP_ON;
+       u32 saveLVDSPP_OFF;
+       u32 saveDVOA;
+       u32 saveDVOB;
+       u32 saveDVOC;
+       u32 savePP_ON;
+       u32 savePP_OFF;
+       u32 savePP_CONTROL;
+       u32 savePP_CYCLE;
+       u32 savePFIT_CONTROL;
+       u32 save_palette_a[256];
+       u32 save_palette_b[256];
+       u32 saveFBC_CFB_BASE;
+       u32 saveFBC_LL_BASE;
+       u32 saveFBC_CONTROL;
+       u32 saveFBC_CONTROL2;
+       u32 saveSWF0[16];
+       u32 saveSWF1[16];
+       u32 saveSWF2[3];
+       u8 saveMSR;
+       u8 saveSR[8];
+       u8 saveGR[24];
+       u8 saveAR_INDEX;
+       u8 saveAR[20];
+       u8 saveDACMASK;
+       u8 saveDACDATA[256*3]; /* 256 3-byte colors */
+       u8 saveCR[36];
 } drm_i915_private_t;
 
 extern struct drm_ioctl_desc i915_ioctls[];
@@ -122,6 +201,7 @@ extern int i915_max_ioctl;
                                /* i915_dma.c */
 extern void i915_kernel_lost_context(struct drm_device * dev);
 extern int i915_driver_load(struct drm_device *, unsigned long flags);
+extern int i915_driver_unload(struct drm_device *);
 extern void i915_driver_lastclose(struct drm_device * dev);
 extern void i915_driver_preclose(struct drm_device *dev,
                                 struct drm_file *file_priv);
@@ -163,7 +243,7 @@ extern void i915_mem_release(struct drm_device * dev,
 
 #define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, (reg))
 #define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
-#define I915_READ16(reg)       DRM_READ16(dev_priv->mmio_map, (reg))
+#define I915_READ16(reg)       DRM_READ16(dev_priv->mmio_map, (reg))
 #define I915_WRITE16(reg,val)  DRM_WRITE16(dev_priv->mmio_map, (reg), (val))
 
 #define I915_VERBOSE 0
@@ -173,9 +253,8 @@ extern void i915_mem_release(struct drm_device * dev,
 
 #define BEGIN_LP_RING(n) do {                          \
        if (I915_VERBOSE)                               \
-               DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",  \
-                         (n), __FUNCTION__);           \
-       if (dev_priv->ring.space < (n)*4)                       \
+               DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n));  \
+       if (dev_priv->ring.space < (n)*4)               \
                i915_wait_ring(dev, (n)*4, __FUNCTION__);               \
        outcount = 0;                                   \
        outring = dev_priv->ring.tail;                  \
@@ -200,7 +279,51 @@ extern void i915_mem_release(struct drm_device * dev,
 
 extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
-#define GFX_OP_USER_INTERRUPT          ((0<<29)|(2<<23))
+/* Extended config space */
+#define LBB 0xf4
+
+/* VGA stuff */
+
+#define VGA_ST01_MDA 0x3ba
+#define VGA_ST01_CGA 0x3da
+
+#define VGA_MSR_WRITE 0x3c2
+#define VGA_MSR_READ 0x3cc
+#define   VGA_MSR_MEM_EN (1<<1)
+#define   VGA_MSR_CGA_MODE (1<<0)
+
+#define VGA_SR_INDEX 0x3c4
+#define VGA_SR_DATA 0x3c5
+
+#define VGA_AR_INDEX 0x3c0
+#define   VGA_AR_VID_EN (1<<5)
+#define VGA_AR_DATA_WRITE 0x3c0
+#define VGA_AR_DATA_READ 0x3c1
+
+#define VGA_GR_INDEX 0x3ce
+#define VGA_GR_DATA 0x3cf
+/* GR05 */
+#define   VGA_GR_MEM_READ_MODE_SHIFT 3
+#define     VGA_GR_MEM_READ_MODE_PLANE 1
+/* GR06 */
+#define   VGA_GR_MEM_MODE_MASK 0xc
+#define   VGA_GR_MEM_MODE_SHIFT 2
+#define   VGA_GR_MEM_A0000_AFFFF 0
+#define   VGA_GR_MEM_A0000_BFFFF 1
+#define   VGA_GR_MEM_B0000_B7FFF 2
+#define   VGA_GR_MEM_B0000_BFFFF 3
+
+#define VGA_DACMASK 0x3c6
+#define VGA_DACRX 0x3c7
+#define VGA_DACWX 0x3c8
+#define VGA_DACDATA 0x3c9
+
+#define VGA_CR_INDEX_MDA 0x3b4
+#define VGA_CR_DATA_MDA 0x3b5
+#define VGA_CR_INDEX_CGA 0x3d4
+#define VGA_CR_DATA_CGA 0x3d5
+
+#define GFX_OP_USER_INTERRUPT          ((0<<29)|(2<<23))
 #define GFX_OP_BREAKPOINT_INTERRUPT    ((0<<29)|(1<<23))
 #define CMD_REPORT_HEAD                        (7<<23)
 #define CMD_STORE_DWORD_IDX            ((0x21<<23) | 0x1)
@@ -215,9 +338,47 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define BB1_UNPROTECTED       (0<<0)
 #define BB2_END_ADDR_MASK     (~0x7)
 
+/* Framebuffer compression */
+#define FBC_CFB_BASE           0x03200 /* 4k page aligned */
+#define FBC_LL_BASE            0x03204 /* 4k page aligned */
+#define FBC_CONTROL            0x03208
+#define   FBC_CTL_EN           (1<<31)
+#define   FBC_CTL_PERIODIC     (1<<30)
+#define   FBC_CTL_INTERVAL_SHIFT (16)
+#define   FBC_CTL_UNCOMPRESSIBLE (1<<14)
+#define   FBC_CTL_STRIDE_SHIFT (5)
+#define   FBC_CTL_FENCENO      (1<<0)
+#define FBC_COMMAND            0x0320c
+#define   FBC_CMD_COMPRESS     (1<<0)
+#define FBC_STATUS             0x03210
+#define   FBC_STAT_COMPRESSING (1<<31)
+#define   FBC_STAT_COMPRESSED  (1<<30)
+#define   FBC_STAT_MODIFIED    (1<<29)
+#define   FBC_STAT_CURRENT_LINE        (1<<0)
+#define FBC_CONTROL2           0x03214
+#define   FBC_CTL_FENCE_DBL    (0<<4)
+#define   FBC_CTL_IDLE_IMM     (0<<2)
+#define   FBC_CTL_IDLE_FULL    (1<<2)
+#define   FBC_CTL_IDLE_LINE    (2<<2)
+#define   FBC_CTL_IDLE_DEBUG   (3<<2)
+#define   FBC_CTL_CPU_FENCE    (1<<1)
+#define   FBC_CTL_PLANEA       (0<<0)
+#define   FBC_CTL_PLANEB       (1<<0)
+#define FBC_FENCE_OFF          0x0321b
+
+#define FBC_LL_SIZE            (1536)
+#define FBC_LL_PAD             (32)
+
+/* Interrupt bits:
+ */
+#define USER_INT_FLAG    (1<<1)
+#define VSYNC_PIPEB_FLAG (1<<5)
+#define VSYNC_PIPEA_FLAG (1<<7)
+#define HWB_OOM_FLAG     (1<<13) /* binner out of memory */
+
 #define I915REG_HWSTAM         0x02098
 #define I915REG_INT_IDENTITY_R 0x020a4
-#define I915REG_INT_MASK_R     0x020a8
+#define I915REG_INT_MASK_R     0x020a8
 #define I915REG_INT_ENABLE_R   0x020a0
 
 #define I915REG_PIPEASTAT      0x70024
@@ -229,7 +390,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define SRX_INDEX              0x3c4
 #define SRX_DATA               0x3c5
 #define SR01                   1
-#define SR01_SCREEN_OFF        (1<<5)
+#define SR01_SCREEN_OFF                (1<<5)
 
 #define PPCR                   0x61204
 #define PPCR_ON                        (1<<0)
@@ -249,31 +410,129 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define ADPA_DPMS_OFF          (3<<10)
 
 #define NOPID                   0x2094
-#define LP_RING                0x2030
-#define HP_RING                0x2040
-#define RING_TAIL                      0x00
+#define LP_RING                        0x2030
+#define HP_RING                        0x2040
+/* The binner has its own ring buffer:
+ */
+#define HWB_RING               0x2400
+
+#define RING_TAIL              0x00
 #define TAIL_ADDR              0x001FFFF8
-#define RING_HEAD                      0x04
-#define HEAD_WRAP_COUNT        0xFFE00000
-#define HEAD_WRAP_ONE          0x00200000
-#define HEAD_ADDR              0x001FFFFC
-#define RING_START                     0x08
-#define START_ADDR             0x0xFFFFF000
-#define RING_LEN                       0x0C
-#define RING_NR_PAGES          0x001FF000
-#define RING_REPORT_MASK       0x00000006
-#define RING_REPORT_64K        0x00000002
-#define RING_REPORT_128K       0x00000004
-#define RING_NO_REPORT         0x00000000
-#define RING_VALID_MASK        0x00000001
-#define RING_VALID             0x00000001
-#define RING_INVALID           0x00000000
+#define RING_HEAD              0x04
+#define HEAD_WRAP_COUNT                0xFFE00000
+#define HEAD_WRAP_ONE          0x00200000
+#define HEAD_ADDR              0x001FFFFC
+#define RING_START             0x08
+#define START_ADDR             0x0xFFFFF000
+#define RING_LEN               0x0C
+#define RING_NR_PAGES          0x001FF000
+#define RING_REPORT_MASK       0x00000006
+#define RING_REPORT_64K                0x00000002
+#define RING_REPORT_128K       0x00000004
+#define RING_NO_REPORT         0x00000000
+#define RING_VALID_MASK                0x00000001
+#define RING_VALID             0x00000001
+#define RING_INVALID           0x00000000
+
+/* Instruction parser error reg:
+ */
+#define IPEIR                  0x2088
+
+/* Scratch pad debug 0 reg:
+ */
+#define SCPD0                  0x209c
+
+/* Error status reg:
+ */
+#define ESR                    0x20b8
+
+/* Secondary DMA fetch address debug reg:
+ */
+#define DMA_FADD_S             0x20d4
+
+/* Cache mode 0 reg.
+ *  - Manipulating render cache behaviour is central
+ *    to the concept of zone rendering, tuning this reg can help avoid
+ *    unnecessary render cache reads and even writes (for z/stencil)
+ *    at beginning and end of scene.
+ *
+ * - To change a bit, write to this reg with a mask bit set and the
+ * bit of interest either set or cleared.  EG: (BIT<<16) | BIT to set.
+ */
+#define Cache_Mode_0           0x2120
+#define CM0_MASK_SHIFT          16
+#define CM0_IZ_OPT_DISABLE      (1<<6)
+#define CM0_ZR_OPT_DISABLE      (1<<5)
+#define CM0_DEPTH_EVICT_DISABLE (1<<4)
+#define CM0_COLOR_EVICT_DISABLE (1<<3)
+#define CM0_DEPTH_WRITE_DISABLE (1<<1)
+#define CM0_RC_OP_FLUSH_DISABLE (1<<0)
+
+
+/* Graphics flush control.  A CPU write flushes the GWB of all writes.
+ * The data is discarded.
+ */
+#define GFX_FLSH_CNTL          0x2170
+
+/* Binner control.  Defines the location of the bin pointer list:
+ */
+#define BINCTL                 0x2420
+#define BC_MASK                        (1 << 9)
+
+/* Binned scene info.
+ */
+#define BINSCENE               0x2428
+#define BS_OP_LOAD             (1 << 8)
+#define BS_MASK                        (1 << 22)
+
+/* Bin command parser debug reg:
+ */
+#define BCPD                   0x2480
+
+/* Bin memory control debug reg:
+ */
+#define BMCD                   0x2484
+
+/* Bin data cache debug reg:
+ */
+#define BDCD                   0x2488
+
+/* Binner pointer cache debug reg:
+ */
+#define BPCD                   0x248c
+
+/* Binner scratch pad debug reg:
+ */
+#define BINSKPD                        0x24f0
+
+/* HWB scratch pad debug reg:
+ */
+#define HWBSKPD                        0x24f4
+
+/* Binner memory pool reg:
+ */
+#define BMP_BUFFER             0x2430
+#define BMP_PAGE_SIZE_4K       (0 << 10)
+#define BMP_BUFFER_SIZE_SHIFT  1
+#define BMP_ENABLE             (1 << 0)
+
+/* Get/put memory from the binner memory pool:
+ */
+#define BMP_GET                        0x2438
+#define BMP_PUT                        0x2440
+#define BMP_OFFSET_SHIFT       5
+
+/* 3D state packets:
+ */
+#define GFX_OP_RASTER_RULES    ((0x3<<29)|(0x7<<24))
 
 #define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
 #define SC_UPDATE_SCISSOR       (0x1<<1)
 #define SC_ENABLE_MASK          (0x1<<0)
 #define SC_ENABLE               (0x1<<0)
 
+#define GFX_OP_LOAD_INDIRECT   ((0x3<<29)|(0x1d<<24)|(0x7<<16))
+
 #define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
 #define SCI_YMIN_MASK      (0xffff<<16)
 #define SCI_XMIN_MASK      (0xffff<<0)
@@ -290,17 +549,19 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
 #define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
 
+#define SRC_COPY_BLT_CMD                ((2<<29)|(0x43<<22)|4)
 #define XY_SRC_COPY_BLT_CMD            ((2<<29)|(0x53<<22)|6)
 #define XY_SRC_COPY_BLT_WRITE_ALPHA    (1<<21)
 #define XY_SRC_COPY_BLT_WRITE_RGB      (1<<20)
 
-#define MI_BATCH_BUFFER        ((0x30<<23)|1)
-#define MI_BATCH_BUFFER_START  (0x31<<23)
-#define MI_BATCH_BUFFER_END    (0xA<<23)
+#define MI_BATCH_BUFFER                ((0x30<<23)|1)
+#define MI_BATCH_BUFFER_START  (0x31<<23)
+#define MI_BATCH_BUFFER_END    (0xA<<23)
 #define MI_BATCH_NON_SECURE    (1)
 #define MI_BATCH_NON_SECURE_I965 (1<<8)
 
 #define MI_WAIT_FOR_EVENT       ((0x3<<23))
+#define MI_WAIT_FOR_PLANE_B_FLIP      (1<<6)
 #define MI_WAIT_FOR_PLANE_A_FLIP      (1<<2)
 #define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
 
@@ -308,9 +569,538 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
 #define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
 #define ASYNC_FLIP                (1<<22)
+#define DISPLAY_PLANE_A           (0<<20)
+#define DISPLAY_PLANE_B           (1<<20)
+
+/* Display regs */
+#define DSPACNTR                0x70180
+#define DSPBCNTR                0x71180
+#define DISPPLANE_SEL_PIPE_MASK                 (1<<24)
+
+/* Define the region of interest for the binner:
+ */
+#define CMD_OP_BIN_CONTROL      ((0x3<<29)|(0x1d<<24)|(0x84<<16)|4)
 
 #define CMD_OP_DESTBUFFER_INFO  ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
 
-#define READ_BREADCRUMB(dev_priv) (((u32 *)(dev_priv->hw_status_page))[5])
+#define CMD_MI_FLUSH         (0x04 << 23)
+#define MI_NO_WRITE_FLUSH    (1 << 2)
+#define MI_READ_FLUSH        (1 << 0)
+#define MI_EXE_FLUSH         (1 << 1)
+#define MI_END_SCENE         (1 << 4) /* flush binner and incr scene count */
+#define MI_SCENE_COUNT       (1 << 3) /* just increment scene count */
+
+#define BREADCRUMB_BITS 31
+#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1)
+
+#define READ_BREADCRUMB(dev_priv)  (((volatile u32*)(dev_priv->hw_status_page))[5])
+#define READ_HWSP(dev_priv, reg)  (((volatile u32*)(dev_priv->hw_status_page))[reg])
+
+#define BLC_PWM_CTL            0x61254
+#define BACKLIGHT_MODULATION_FREQ_SHIFT                (17)
+
+#define BLC_PWM_CTL2           0x61250
+/**
+ * This is the most significant 15 bits of the number of backlight cycles in a
+ * complete cycle of the modulated backlight control.
+ *
+ * The actual value is this field multiplied by two.
+ */
+#define BACKLIGHT_MODULATION_FREQ_MASK         (0x7fff << 17)
+#define BLM_LEGACY_MODE                                (1 << 16)
+/**
+ * This is the number of cycles out of the backlight modulation cycle for which
+ * the backlight is on.
+ *
+ * This field must be no greater than the number of cycles in the complete
+ * backlight modulation cycle.
+ */
+#define BACKLIGHT_DUTY_CYCLE_SHIFT             (0)
+#define BACKLIGHT_DUTY_CYCLE_MASK              (0xffff)
+
+#define I915_GCFGC                     0xf0
+#define I915_LOW_FREQUENCY_ENABLE              (1 << 7)
+#define I915_DISPLAY_CLOCK_190_200_MHZ         (0 << 4)
+#define I915_DISPLAY_CLOCK_333_MHZ             (4 << 4)
+#define I915_DISPLAY_CLOCK_MASK                        (7 << 4)
+
+#define I855_HPLLCC                    0xc0
+#define I855_CLOCK_CONTROL_MASK                        (3 << 0)
+#define I855_CLOCK_133_200                     (0 << 0)
+#define I855_CLOCK_100_200                     (1 << 0)
+#define I855_CLOCK_100_133                     (2 << 0)
+#define I855_CLOCK_166_250                     (3 << 0)
+
+/* p317, 319
+ */
+#define VCLK2_VCO_M        0x6008 /* treat as 16 bit? (includes msbs) */
+#define VCLK2_VCO_N        0x600a
+#define VCLK2_VCO_DIV_SEL  0x6012
+
+#define VCLK_DIVISOR_VGA0   0x6000
+#define VCLK_DIVISOR_VGA1   0x6004
+#define VCLK_POST_DIV      0x6010
+/** Selects a post divisor of 4 instead of 2. */
+# define VGA1_PD_P2_DIV_4      (1 << 15)
+/** Overrides the p2 post divisor field */
+# define VGA1_PD_P1_DIV_2      (1 << 13)
+# define VGA1_PD_P1_SHIFT      8
+/** P1 value is 2 greater than this field */
+# define VGA1_PD_P1_MASK       (0x1f << 8)
+/** Selects a post divisor of 4 instead of 2. */
+# define VGA0_PD_P2_DIV_4      (1 << 7)
+/** Overrides the p2 post divisor field */
+# define VGA0_PD_P1_DIV_2      (1 << 5)
+# define VGA0_PD_P1_SHIFT      0
+/** P1 value is 2 greater than this field */
+# define VGA0_PD_P1_MASK       (0x1f << 0)
+
+/* I830 CRTC registers */
+#define HTOTAL_A       0x60000
+#define HBLANK_A       0x60004
+#define HSYNC_A                0x60008
+#define VTOTAL_A       0x6000c
+#define VBLANK_A       0x60010
+#define VSYNC_A                0x60014
+#define PIPEASRC       0x6001c
+#define BCLRPAT_A      0x60020
+#define VSYNCSHIFT_A   0x60028
+
+#define HTOTAL_B       0x61000
+#define HBLANK_B       0x61004
+#define HSYNC_B                0x61008
+#define VTOTAL_B       0x6100c
+#define VBLANK_B       0x61010
+#define VSYNC_B                0x61014
+#define PIPEBSRC       0x6101c
+#define BCLRPAT_B      0x61020
+#define VSYNCSHIFT_B   0x61028
+
+#define PP_STATUS      0x61200
+# define PP_ON                                 (1 << 31)
+/**
+ * Indicates that all dependencies of the panel are on:
+ *
+ * - PLL enabled
+ * - pipe enabled
+ * - LVDS/DVOB/DVOC on
+ */
+# define PP_READY                              (1 << 30)
+# define PP_SEQUENCE_NONE                      (0 << 28)
+# define PP_SEQUENCE_ON                                (1 << 28)
+# define PP_SEQUENCE_OFF                       (2 << 28)
+# define PP_SEQUENCE_MASK                      0x30000000
+#define PP_CONTROL     0x61204
+# define POWER_TARGET_ON                       (1 << 0)
+
+#define LVDSPP_ON       0x61208
+#define LVDSPP_OFF      0x6120c
+#define PP_CYCLE        0x61210
+
+#define PFIT_CONTROL   0x61230
+# define PFIT_ENABLE                           (1 << 31)
+# define PFIT_PIPE_MASK                                (3 << 29)
+# define PFIT_PIPE_SHIFT                       29
+# define VERT_INTERP_DISABLE                   (0 << 10)
+# define VERT_INTERP_BILINEAR                  (1 << 10)
+# define VERT_INTERP_MASK                      (3 << 10)
+# define VERT_AUTO_SCALE                       (1 << 9)
+# define HORIZ_INTERP_DISABLE                  (0 << 6)
+# define HORIZ_INTERP_BILINEAR                 (1 << 6)
+# define HORIZ_INTERP_MASK                     (3 << 6)
+# define HORIZ_AUTO_SCALE                      (1 << 5)
+# define PANEL_8TO6_DITHER_ENABLE              (1 << 3)
+
+#define PFIT_PGM_RATIOS        0x61234
+# define PFIT_VERT_SCALE_MASK                  0xfff00000
+# define PFIT_HORIZ_SCALE_MASK                 0x0000fff0
+
+#define PFIT_AUTO_RATIOS       0x61238
+
+
+#define DPLL_A         0x06014
+#define DPLL_B         0x06018
+# define DPLL_VCO_ENABLE                       (1 << 31)
+# define DPLL_DVO_HIGH_SPEED                   (1 << 30)
+# define DPLL_SYNCLOCK_ENABLE                  (1 << 29)
+# define DPLL_VGA_MODE_DIS                     (1 << 28)
+# define DPLLB_MODE_DAC_SERIAL                 (1 << 26) /* i915 */
+# define DPLLB_MODE_LVDS                       (2 << 26) /* i915 */
+# define DPLL_MODE_MASK                                (3 << 26)
+# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10       (0 << 24) /* i915 */
+# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5                (1 << 24) /* i915 */
+# define DPLLB_LVDS_P2_CLOCK_DIV_14            (0 << 24) /* i915 */
+# define DPLLB_LVDS_P2_CLOCK_DIV_7             (1 << 24) /* i915 */
+# define DPLL_P2_CLOCK_DIV_MASK                        0x03000000 /* i915 */
+# define DPLL_FPA01_P1_POST_DIV_MASK           0x00ff0000 /* i915 */
+/**
+ *  The i830 generation, in DAC/serial mode, defines p1 as two plus this
+ * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set.
+ */
+# define DPLL_FPA01_P1_POST_DIV_MASK_I830      0x001f0000
+/**
+ * The i830 generation, in LVDS mode, defines P1 as the bit number set within
+ * this field (only one bit may be set).
+ */
+# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000
+# define DPLL_FPA01_P1_POST_DIV_SHIFT          16
+# define PLL_P2_DIVIDE_BY_4                    (1 << 23) /* i830, required in DVO non-gang */
+# define PLL_P1_DIVIDE_BY_TWO                  (1 << 21) /* i830 */
+# define PLL_REF_INPUT_DREFCLK                 (0 << 13)
+# define PLL_REF_INPUT_TVCLKINA                        (1 << 13) /* i830 */
+# define PLL_REF_INPUT_TVCLKINBC               (2 << 13) /* SDVO TVCLKIN */
+# define PLLB_REF_INPUT_SPREADSPECTRUMIN       (3 << 13)
+# define PLL_REF_INPUT_MASK                    (3 << 13)
+# define PLL_LOAD_PULSE_PHASE_SHIFT            9
+/*
+ * Parallel to Serial Load Pulse phase selection.
+ * Selects the phase for the 10X DPLL clock for the PCIe
+ * digital display port. The range is 4 to 13; 10 or more
+ * is just a flip delay. The default is 6
+ */
+# define PLL_LOAD_PULSE_PHASE_MASK             (0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
+# define DISPLAY_RATE_SELECT_FPA1              (1 << 8)
+
+/**
+ * SDVO multiplier for 945G/GM. Not used on 965.
+ *
+ * \sa DPLL_MD_UDI_MULTIPLIER_MASK
+ */
+# define SDVO_MULTIPLIER_MASK                  0x000000ff
+# define SDVO_MULTIPLIER_SHIFT_HIRES           4
+# define SDVO_MULTIPLIER_SHIFT_VGA             0
+
+/** @defgroup DPLL_MD
+ * @{
+ */
+/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */
+#define DPLL_A_MD              0x0601c
+/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */
+#define DPLL_B_MD              0x06020
+/**
+ * UDI pixel divider, controlling how many pixels are stuffed into a packet.
+ *
+ * Value is pixels minus 1.  Must be set to 1 pixel for SDVO.
+ */
+# define DPLL_MD_UDI_DIVIDER_MASK              0x3f000000
+# define DPLL_MD_UDI_DIVIDER_SHIFT             24
+/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */
+# define DPLL_MD_VGA_UDI_DIVIDER_MASK          0x003f0000
+# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT         16
+/**
+ * SDVO/UDI pixel multiplier.
+ *
+ * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus
+ * clock rate is 10 times the DPLL clock.  At low resolution/refresh rate
+ * modes, the bus rate would be below the limits, so SDVO allows for stuffing
+ * dummy bytes in the datastream at an increased clock rate, with both sides of
+ * the link knowing how many bytes are fill.
+ *
+ * So, for a mode with a dotclock of 65Mhz, we would want to double the clock
+ * rate to 130Mhz to get a bus rate of 1.30Ghz.  The DPLL clock rate would be
+ * set to 130Mhz, and the SDVO multiplier set to 2x in this register and
+ * through an SDVO command.
+ *
+ * This register field has values of multiplication factor minus 1, with
+ * a maximum multiplier of 5 for SDVO.
+ */
+# define DPLL_MD_UDI_MULTIPLIER_MASK           0x00003f00
+# define DPLL_MD_UDI_MULTIPLIER_SHIFT          8
+/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK.
+ * This best be set to the default value (3) or the CRT won't work. No,
+ * I don't entirely understand what this does...
+ */
+# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK       0x0000003f
+# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT      0
+/** @} */
+
+#define DPLL_TEST              0x606c
+# define DPLLB_TEST_SDVO_DIV_1                 (0 << 22)
+# define DPLLB_TEST_SDVO_DIV_2                 (1 << 22)
+# define DPLLB_TEST_SDVO_DIV_4                 (2 << 22)
+# define DPLLB_TEST_SDVO_DIV_MASK              (3 << 22)
+# define DPLLB_TEST_N_BYPASS                   (1 << 19)
+# define DPLLB_TEST_M_BYPASS                   (1 << 18)
+# define DPLLB_INPUT_BUFFER_ENABLE             (1 << 16)
+# define DPLLA_TEST_N_BYPASS                   (1 << 3)
+# define DPLLA_TEST_M_BYPASS                   (1 << 2)
+# define DPLLA_INPUT_BUFFER_ENABLE             (1 << 0)
+
+#define ADPA                   0x61100
+#define ADPA_DAC_ENABLE                (1<<31)
+#define ADPA_DAC_DISABLE       0
+#define ADPA_PIPE_SELECT_MASK  (1<<30)
+#define ADPA_PIPE_A_SELECT     0
+#define ADPA_PIPE_B_SELECT     (1<<30)
+#define ADPA_USE_VGA_HVPOLARITY (1<<15)
+#define ADPA_SETS_HVPOLARITY   0
+#define ADPA_VSYNC_CNTL_DISABLE (1<<11)
+#define ADPA_VSYNC_CNTL_ENABLE 0
+#define ADPA_HSYNC_CNTL_DISABLE (1<<10)
+#define ADPA_HSYNC_CNTL_ENABLE 0
+#define ADPA_VSYNC_ACTIVE_HIGH (1<<4)
+#define ADPA_VSYNC_ACTIVE_LOW  0
+#define ADPA_HSYNC_ACTIVE_HIGH (1<<3)
+#define ADPA_HSYNC_ACTIVE_LOW  0
+
+#define FPA0           0x06040
+#define FPA1           0x06044
+#define FPB0           0x06048
+#define FPB1           0x0604c
+# define FP_N_DIV_MASK                         0x003f0000
+# define FP_N_DIV_SHIFT                                16
+# define FP_M1_DIV_MASK                                0x00003f00
+# define FP_M1_DIV_SHIFT                       8
+# define FP_M2_DIV_MASK                                0x0000003f
+# define FP_M2_DIV_SHIFT                       0
+
+
+#define PORT_HOTPLUG_EN                0x61110
+# define SDVOB_HOTPLUG_INT_EN                  (1 << 26)
+# define SDVOC_HOTPLUG_INT_EN                  (1 << 25)
+# define TV_HOTPLUG_INT_EN                     (1 << 18)
+# define CRT_HOTPLUG_INT_EN                    (1 << 9)
+# define CRT_HOTPLUG_FORCE_DETECT              (1 << 3)
+
+#define PORT_HOTPLUG_STAT      0x61114
+# define CRT_HOTPLUG_INT_STATUS                        (1 << 11)
+# define TV_HOTPLUG_INT_STATUS                 (1 << 10)
+# define CRT_HOTPLUG_MONITOR_MASK              (3 << 8)
+# define CRT_HOTPLUG_MONITOR_COLOR             (3 << 8)
+# define CRT_HOTPLUG_MONITOR_MONO              (2 << 8)
+# define CRT_HOTPLUG_MONITOR_NONE              (0 << 8)
+# define SDVOC_HOTPLUG_INT_STATUS              (1 << 7)
+# define SDVOB_HOTPLUG_INT_STATUS              (1 << 6)
+
+#define SDVOB                  0x61140
+#define SDVOC                  0x61160
+#define SDVO_ENABLE                            (1 << 31)
+#define SDVO_PIPE_B_SELECT                     (1 << 30)
+#define SDVO_STALL_SELECT                      (1 << 29)
+#define SDVO_INTERRUPT_ENABLE                  (1 << 26)
+/**
+ * 915G/GM SDVO pixel multiplier.
+ *
+ * Programmed value is multiplier - 1, up to 5x.
+ *
+ * \sa DPLL_MD_UDI_MULTIPLIER_MASK
+ */
+#define SDVO_PORT_MULTIPLY_MASK                        (7 << 23)
+#define SDVO_PORT_MULTIPLY_SHIFT               23
+#define SDVO_PHASE_SELECT_MASK                 (15 << 19)
+#define SDVO_PHASE_SELECT_DEFAULT              (6 << 19)
+#define SDVO_CLOCK_OUTPUT_INVERT               (1 << 18)
+#define SDVOC_GANG_MODE                                (1 << 16)
+#define SDVO_BORDER_ENABLE                     (1 << 7)
+#define SDVOB_PCIE_CONCURRENCY                 (1 << 3)
+#define SDVO_DETECTED                          (1 << 2)
+/* Bits to be preserved when writing */
+#define SDVOB_PRESERVE_MASK                    ((1 << 17) | (1 << 16) | (1 << 14))
+#define SDVOC_PRESERVE_MASK                    (1 << 17)
+
+/** @defgroup LVDS
+ * @{
+ */
+/**
+ * This register controls the LVDS output enable, pipe selection, and data
+ * format selection.
+ *
+ * All of the clock/data pairs are force powered down by power sequencing.
+ */
+#define LVDS                   0x61180
+/**
+ * Enables the LVDS port.  This bit must be set before DPLLs are enabled, as
+ * the DPLL semantics change when the LVDS is assigned to that pipe.
+ */
+# define LVDS_PORT_EN                  (1 << 31)
+/** Selects pipe B for LVDS data.  Must be set on pre-965. */
+# define LVDS_PIPEB_SELECT             (1 << 30)
+
+/**
+ * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per
+ * pixel.
+ */
+# define LVDS_A0A2_CLKA_POWER_MASK     (3 << 8)
+# define LVDS_A0A2_CLKA_POWER_DOWN     (0 << 8)
+# define LVDS_A0A2_CLKA_POWER_UP       (3 << 8)
+/**
+ * Controls the A3 data pair, which contains the additional LSBs for 24 bit
+ * mode.  Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be
+ * on.
+ */
+# define LVDS_A3_POWER_MASK            (3 << 6)
+# define LVDS_A3_POWER_DOWN            (0 << 6)
+# define LVDS_A3_POWER_UP              (3 << 6)
+/**
+ * Controls the CLKB pair.  This should only be set when LVDS_B0B3_POWER_UP
+ * is set.
+ */
+# define LVDS_CLKB_POWER_MASK          (3 << 4)
+# define LVDS_CLKB_POWER_DOWN          (0 << 4)
+# define LVDS_CLKB_POWER_UP            (3 << 4)
+
+/**
+ * Controls the B0-B3 data pairs.  This must be set to match the DPLL p2
+ * setting for whether we are in dual-channel mode.  The B3 pair will
+ * additionally only be powered up when LVDS_A3_POWER_UP is set.
+ */
+# define LVDS_B0B3_POWER_MASK          (3 << 2)
+# define LVDS_B0B3_POWER_DOWN          (0 << 2)
+# define LVDS_B0B3_POWER_UP            (3 << 2)
+
+#define PIPEACONF 0x70008
+#define PIPEACONF_ENABLE       (1<<31)
+#define PIPEACONF_DISABLE      0
+#define PIPEACONF_DOUBLE_WIDE  (1<<30)
+#define I965_PIPECONF_ACTIVE   (1<<30)
+#define PIPEACONF_SINGLE_WIDE  0
+#define PIPEACONF_PIPE_UNLOCKED 0
+#define PIPEACONF_PIPE_LOCKED  (1<<25)
+#define PIPEACONF_PALETTE      0
+#define PIPEACONF_GAMMA                (1<<24)
+#define PIPECONF_FORCE_BORDER  (1<<25)
+#define PIPECONF_PROGRESSIVE   (0 << 21)
+#define PIPECONF_INTERLACE_W_FIELD_INDICATION  (6 << 21)
+#define PIPECONF_INTERLACE_FIELD_0_ONLY                (7 << 21)
+
+#define PIPEBCONF 0x71008
+#define PIPEBCONF_ENABLE       (1<<31)
+#define PIPEBCONF_DISABLE      0
+#define PIPEBCONF_DOUBLE_WIDE  (1<<30)
+#define PIPEBCONF_DISABLE      0
+#define PIPEBCONF_GAMMA                (1<<24)
+#define PIPEBCONF_PALETTE      0
+
+#define PIPEBGCMAXRED          0x71010
+#define PIPEBGCMAXGREEN                0x71014
+#define PIPEBGCMAXBLUE         0x71018
+#define PIPEBSTAT              0x71024
+#define PIPEBFRAMEHIGH         0x71040
+#define PIPEBFRAMEPIXEL                0x71044
+
+#define DSPACNTR               0x70180
+#define DSPBCNTR               0x71180
+#define DISPLAY_PLANE_ENABLE                   (1<<31)
+#define DISPLAY_PLANE_DISABLE                  0
+#define DISPPLANE_GAMMA_ENABLE                 (1<<30)
+#define DISPPLANE_GAMMA_DISABLE                        0
+#define DISPPLANE_PIXFORMAT_MASK               (0xf<<26)
+#define DISPPLANE_8BPP                         (0x2<<26)
+#define DISPPLANE_15_16BPP                     (0x4<<26)
+#define DISPPLANE_16BPP                                (0x5<<26)
+#define DISPPLANE_32BPP_NO_ALPHA               (0x6<<26)
+#define DISPPLANE_32BPP                                (0x7<<26)
+#define DISPPLANE_STEREO_ENABLE                        (1<<25)
+#define DISPPLANE_STEREO_DISABLE               0
+#define DISPPLANE_SEL_PIPE_MASK                        (1<<24)
+#define DISPPLANE_SEL_PIPE_A                   0
+#define DISPPLANE_SEL_PIPE_B                   (1<<24)
+#define DISPPLANE_SRC_KEY_ENABLE               (1<<22)
+#define DISPPLANE_SRC_KEY_DISABLE              0
+#define DISPPLANE_LINE_DOUBLE                  (1<<20)
+#define DISPPLANE_NO_LINE_DOUBLE               0
+#define DISPPLANE_STEREO_POLARITY_FIRST                0
+#define DISPPLANE_STEREO_POLARITY_SECOND       (1<<18)
+/* plane B only */
+#define DISPPLANE_ALPHA_TRANS_ENABLE           (1<<15)
+#define DISPPLANE_ALPHA_TRANS_DISABLE          0
+#define DISPPLANE_SPRITE_ABOVE_DISPLAYA                0
+#define DISPPLANE_SPRITE_ABOVE_OVERLAY         (1)
+
+#define DSPABASE               0x70184
+#define DSPASTRIDE             0x70188
+
+#define DSPBBASE               0x71184
+#define DSPBADDR               DSPBBASE
+#define DSPBSTRIDE             0x71188
+
+#define DSPAKEYVAL             0x70194
+#define DSPAKEYMASK            0x70198
+
+#define DSPAPOS                        0x7018C /* reserved */
+#define DSPASIZE               0x70190
+#define DSPBPOS                        0x7118C
+#define DSPBSIZE               0x71190
+
+#define DSPASURF               0x7019C
+#define DSPATILEOFF            0x701A4
+
+#define DSPBSURF               0x7119C
+#define DSPBTILEOFF            0x711A4
+
+#define VGACNTRL               0x71400
+# define VGA_DISP_DISABLE                      (1 << 31)
+# define VGA_2X_MODE                           (1 << 30)
+# define VGA_PIPE_B_SELECT                     (1 << 29)
+
+/*
+ * Some BIOS scratch area registers.  The 845 (and 830?) store the amount
+ * of video memory available to the BIOS in SWF1.
+ */
+
+#define SWF0                   0x71410
+
+/*
+ * 855 scratch registers.
+ */
+#define SWF10                  0x70410
+
+#define SWF30                  0x72414
+
+/*
+ * Overlay registers.  These are overlay registers accessed via MMIO.
+ * Those loaded via the overlay register page are defined in i830_video.c.
+ */
+#define OVADD                  0x30000
+
+#define DOVSTA                 0x30008
+#define OC_BUF                 (0x3<<20)
+
+#define OGAMC5                 0x30010
+#define OGAMC4                 0x30014
+#define OGAMC3                 0x30018
+#define OGAMC2                 0x3001c
+#define OGAMC1                 0x30020
+#define OGAMC0                 0x30024
+/*
+ * Palette registers
+ */
+#define PALETTE_A              0x0a000
+#define PALETTE_B              0x0a800
+
+#define IS_I830(dev) ((dev)->pci_device == 0x3577)
+#define IS_845G(dev) ((dev)->pci_device == 0x2562)
+#define IS_I85X(dev) ((dev)->pci_device == 0x3582)
+#define IS_I855(dev) ((dev)->pci_device == 0x3582)
+#define IS_I865G(dev) ((dev)->pci_device == 0x2572)
+
+#define IS_I915G(dev) ((dev)->pci_device == 0x2582 || (dev)->pci_device == 0x258a)
+#define IS_I915GM(dev) ((dev)->pci_device == 0x2592)
+#define IS_I945G(dev) ((dev)->pci_device == 0x2772)
+#define IS_I945GM(dev) ((dev)->pci_device == 0x27A2)
+
+#define IS_I965G(dev) ((dev)->pci_device == 0x2972 || \
+                      (dev)->pci_device == 0x2982 || \
+                      (dev)->pci_device == 0x2992 || \
+                      (dev)->pci_device == 0x29A2 || \
+                      (dev)->pci_device == 0x2A02 || \
+                      (dev)->pci_device == 0x2A12 || \
+                      (dev)->pci_device == 0x2A42)
+
+#define IS_I965GM(dev) ((dev)->pci_device == 0x2A02)
+
+#define IS_IGD_GM(dev) ((dev)->pci_device == 0x2A42)
+
+#define IS_G33(dev)    ((dev)->pci_device == 0x29C2 || \
+                       (dev)->pci_device == 0x29B2 ||  \
+                       (dev)->pci_device == 0x29D2)
+
+#define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \
+                     IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev))
+
+#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
+                       IS_I945GM(dev) || IS_I965GM(dev) || IS_IGD_GM(dev))
+
+#define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
 #endif
index a443f4a202e3889c1a52adc43ac1d3020a9351e9..92653b38e64c5e26b5306811f6e32be1d54e16a1 100644 (file)
@@ -276,7 +276,7 @@ static int i915_emit_irq(struct drm_device * dev)
 
        i915_kernel_lost_context(dev);
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
 
@@ -291,7 +291,7 @@ static int i915_emit_irq(struct drm_device * dev)
        OUT_RING(0);
        OUT_RING(GFX_OP_USER_INTERRUPT);
        ADVANCE_LP_RING();
-       
+
        return dev_priv->counter;
 }
 
@@ -300,7 +300,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int ret = 0;
 
-       DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
+       DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
                  READ_BREADCRUMB(dev_priv));
 
        if (READ_BREADCRUMB(dev_priv) >= irq_nr)
@@ -312,8 +312,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
                    READ_BREADCRUMB(dev_priv) >= irq_nr);
 
        if (ret == -EBUSY) {
-               DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
-                         __FUNCTION__,
+               DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
                          READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
        }
 
@@ -329,14 +328,14 @@ static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequ
        int ret = 0;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
        DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
                    (((cur_vblank = atomic_read(counter))
                        - *sequence) <= (1<<23)));
-       
+
        *sequence = cur_vblank;
 
        return ret;
@@ -365,7 +364,7 @@ int i915_irq_emit(struct drm_device *dev, void *data,
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -388,7 +387,7 @@ int i915_irq_wait(struct drm_device *dev, void *data,
        drm_i915_irq_wait_t *irqwait = data;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -418,13 +417,12 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,
        drm_i915_vblank_pipe_t *pipe = data;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
        if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
-               DRM_ERROR("%s called with invalid pipe 0x%x\n", 
-                         __FUNCTION__, pipe->pipe);
+               DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe);
                return -EINVAL;
        }
 
@@ -443,7 +441,7 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
        u16 flag;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -555,7 +553,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
 
        spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
 
-       list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head);
+       list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head);
        dev_priv->swaps_pending++;
 
        spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
index 56fb9b30a5d7453aa824a31b1e6ec93c988d5c6d..6126a60dc9cb19ceb335b9e335a04ecfe6d25559 100644 (file)
@@ -276,7 +276,7 @@ int i915_mem_alloc(struct drm_device *dev, void *data,
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -314,7 +314,7 @@ int i915_mem_free(struct drm_device *dev, void *data,
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -342,7 +342,7 @@ int i915_mem_init_heap(struct drm_device *dev, void *data,
        struct mem_block **heap;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -366,7 +366,7 @@ int i915_mem_destroy_heap( struct drm_device *dev, void *data,
        struct mem_block **heap;
 
        if ( !dev_priv ) {
-               DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+               DRM_ERROR( "called with no initialization\n" );
                return -EINVAL;
        }
 
@@ -375,7 +375,7 @@ int i915_mem_destroy_heap( struct drm_device *dev, void *data,
                DRM_ERROR("get_heap failed");
                return -EFAULT;
        }
-       
+
        if (!*heap) {
                DRM_ERROR("heap not initialized?");
                return -EFAULT;
@@ -384,4 +384,3 @@ int i915_mem_destroy_heap( struct drm_device *dev, void *data,
        i915_mem_takedown( heap );
        return 0;
 }
-
index c567c34cda78e27582bcff4a2e562178e62e23a3..c1d12dbfa8d8dec82e47c7821561e06da9744417 100644 (file)
@@ -493,7 +493,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
                          dma_bs->agp_size);
                return err;
        }
-       
+
        dev_priv->agp_size = agp_size;
        dev_priv->agp_handle = agp_req.handle;
 
@@ -550,7 +550,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
        {
                struct drm_map_list *_entry;
                unsigned long agp_token = 0;
-               
+
                list_for_each_entry(_entry, &dev->maplist, head) {
                        if (_entry->map == dev->agp_buffer_map)
                                agp_token = _entry->user_token;
@@ -964,7 +964,7 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
 
                                free_req.handle = dev_priv->agp_handle;
                                drm_agp_free(dev, &free_req);
-       
+
                                dev_priv->agp_textures = NULL;
                                dev_priv->agp_size = 0;
                                dev_priv->agp_handle = 0;
@@ -998,7 +998,7 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
                }
        }
 
-       return 0;
+       return err;
 }
 
 int mga_dma_init(struct drm_device *dev, void *data,
@@ -1050,7 +1050,7 @@ int mga_dma_flush(struct drm_device *dev, void *data,
 #if MGA_DMA_DEBUG
                int ret = mga_do_wait_for_idle(dev_priv);
                if (ret < 0)
-                       DRM_INFO("%s: -EBUSY\n", __FUNCTION__);
+                       DRM_INFO("-EBUSY\n");
                return ret;
 #else
                return mga_do_wait_for_idle(dev_priv);
index cd94c04e31c00cefa787168aa1f33887d091f7a5..f6ebd24bd5871ebad2204c64195e3e3e31219401 100644 (file)
@@ -216,8 +216,8 @@ static inline u32 _MGA_READ(u32 * addr)
 #define MGA_WRITE( reg, val )  DRM_WRITE32(dev_priv->mmio, (reg), (val))
 #endif
 
-#define DWGREG0        0x1c00
-#define DWGREG0_END    0x1dff
+#define DWGREG0                0x1c00
+#define DWGREG0_END    0x1dff
 #define DWGREG1                0x2c00
 #define DWGREG1_END    0x2dff
 
@@ -249,7 +249,7 @@ do {                                                                        \
                } else if ( dev_priv->prim.space <                      \
                            dev_priv->prim.high_mark ) {                \
                        if ( MGA_DMA_DEBUG )                            \
-                               DRM_INFO( "%s: wrap...\n", __FUNCTION__ );      \
+                               DRM_INFO( "wrap...\n");         \
                        return -EBUSY;                  \
                }                                                       \
        }                                                               \
@@ -260,7 +260,7 @@ do {                                                                        \
        if ( test_bit( 0, &dev_priv->prim.wrapped ) ) {                 \
                if ( mga_do_wait_for_idle( dev_priv ) < 0 ) {           \
                        if ( MGA_DMA_DEBUG )                            \
-                               DRM_INFO( "%s: wrap...\n", __FUNCTION__ );      \
+                               DRM_INFO( "wrap...\n");         \
                        return -EBUSY;                  \
                }                                                       \
                mga_do_dma_wrap_end( dev_priv );                        \
@@ -280,8 +280,7 @@ do {                                                                        \
 #define BEGIN_DMA( n )                                                 \
 do {                                                                   \
        if ( MGA_VERBOSE ) {                                            \
-               DRM_INFO( "BEGIN_DMA( %d ) in %s\n",                    \
-                         (n), __FUNCTION__ );                          \
+               DRM_INFO( "BEGIN_DMA( %d )\n", (n) );           \
                DRM_INFO( "   space=0x%x req=0x%Zx\n",                  \
                          dev_priv->prim.space, (n) * DMA_BLOCK_SIZE ); \
        }                                                               \
@@ -292,7 +291,7 @@ do {                                                                        \
 #define BEGIN_DMA_WRAP()                                               \
 do {                                                                   \
        if ( MGA_VERBOSE ) {                                            \
-               DRM_INFO( "BEGIN_DMA() in %s\n", __FUNCTION__ );                \
+               DRM_INFO( "BEGIN_DMA()\n" );                            \
                DRM_INFO( "   space=0x%x\n", dev_priv->prim.space );    \
        }                                                               \
        prim = dev_priv->prim.start;                                    \
@@ -311,7 +310,7 @@ do {                                                                        \
 #define FLUSH_DMA()                                                    \
 do {                                                                   \
        if ( 0 ) {                                                      \
-               DRM_INFO( "%s:\n", __FUNCTION__ );                              \
+               DRM_INFO( "\n" );                                       \
                DRM_INFO( "   tail=0x%06x head=0x%06lx\n",              \
                          dev_priv->prim.tail,                          \
                          MGA_READ( MGA_PRIMADDRESS ) -                 \
@@ -394,22 +393,22 @@ do {                                                                      \
 #define MGA_VINTCLR                    (1 << 4)
 #define MGA_VINTEN                     (1 << 5)
 
-#define MGA_ALPHACTRL                  0x2c7c
-#define MGA_AR0                        0x1c60
-#define MGA_AR1                        0x1c64
-#define MGA_AR2                        0x1c68
-#define MGA_AR3                        0x1c6c
-#define MGA_AR4                        0x1c70
-#define MGA_AR5                        0x1c74
-#define MGA_AR6                        0x1c78
+#define MGA_ALPHACTRL                  0x2c7c
+#define MGA_AR0                                0x1c60
+#define MGA_AR1                                0x1c64
+#define MGA_AR2                                0x1c68
+#define MGA_AR3                                0x1c6c
+#define MGA_AR4                                0x1c70
+#define MGA_AR5                                0x1c74
+#define MGA_AR6                                0x1c78
 
 #define MGA_CXBNDRY                    0x1c80
-#define MGA_CXLEFT                     0x1ca0
+#define MGA_CXLEFT                     0x1ca0
 #define MGA_CXRIGHT                    0x1ca4
 
-#define MGA_DMAPAD                     0x1c54
-#define MGA_DSTORG                     0x2cb8
-#define MGA_DWGCTL                     0x1c00
+#define MGA_DMAPAD                     0x1c54
+#define MGA_DSTORG                     0x2cb8
+#define MGA_DWGCTL                     0x1c00
 #      define MGA_OPCOD_MASK                   (15 << 0)
 #      define MGA_OPCOD_TRAP                   (4 << 0)
 #      define MGA_OPCOD_TEXTURE_TRAP           (6 << 0)
@@ -455,27 +454,27 @@ do {                                                                      \
 #      define MGA_CLIPDIS                      (1 << 31)
 #define MGA_DWGSYNC                    0x2c4c
 
-#define MGA_FCOL                       0x1c24
-#define MGA_FIFOSTATUS                         0x1e10
-#define MGA_FOGCOL                     0x1cf4
+#define MGA_FCOL                       0x1c24
+#define MGA_FIFOSTATUS                 0x1e10
+#define MGA_FOGCOL                     0x1cf4
 #define MGA_FXBNDRY                    0x1c84
-#define MGA_FXLEFT                     0x1ca8
+#define MGA_FXLEFT                     0x1ca8
 #define MGA_FXRIGHT                    0x1cac
 
-#define MGA_ICLEAR                     0x1e18
+#define MGA_ICLEAR                     0x1e18
 #      define MGA_SOFTRAPICLR                  (1 << 0)
 #      define MGA_VLINEICLR                    (1 << 5)
-#define MGA_IEN                        0x1e1c
+#define MGA_IEN                                0x1e1c
 #      define MGA_SOFTRAPIEN                   (1 << 0)
 #      define MGA_VLINEIEN                     (1 << 5)
 
-#define MGA_LEN                        0x1c5c
+#define MGA_LEN                                0x1c5c
 
 #define MGA_MACCESS                    0x1c04
 
-#define MGA_PITCH                      0x1c8c
-#define MGA_PLNWT                      0x1c1c
-#define MGA_PRIMADDRESS                0x1e58
+#define MGA_PITCH                      0x1c8c
+#define MGA_PLNWT                      0x1c1c
+#define MGA_PRIMADDRESS                        0x1e58
 #      define MGA_DMA_GENERAL                  (0 << 0)
 #      define MGA_DMA_BLIT                     (1 << 0)
 #      define MGA_DMA_VECTOR                   (2 << 0)
@@ -487,43 +486,43 @@ do {                                                                      \
 #      define MGA_PRIMPTREN0                   (1 << 0)
 #      define MGA_PRIMPTREN1                   (1 << 1)
 
-#define MGA_RST                        0x1e40
+#define MGA_RST                                0x1e40
 #      define MGA_SOFTRESET                    (1 << 0)
 #      define MGA_SOFTEXTRST                   (1 << 1)
 
-#define MGA_SECADDRESS                         0x2c40
-#define MGA_SECEND                     0x2c44
-#define MGA_SETUPADDRESS               0x2cd0
-#define MGA_SETUPEND                   0x2cd4
+#define MGA_SECADDRESS                 0x2c40
+#define MGA_SECEND                     0x2c44
+#define MGA_SETUPADDRESS               0x2cd0
+#define MGA_SETUPEND                   0x2cd4
 #define MGA_SGN                                0x1c58
 #define MGA_SOFTRAP                    0x2c48
-#define MGA_SRCORG                     0x2cb4
+#define MGA_SRCORG                     0x2cb4
 #      define MGA_SRMMAP_MASK                  (1 << 0)
 #      define MGA_SRCMAP_FB                    (0 << 0)
 #      define MGA_SRCMAP_SYSMEM                (1 << 0)
 #      define MGA_SRCACC_MASK                  (1 << 1)
 #      define MGA_SRCACC_PCI                   (0 << 1)
 #      define MGA_SRCACC_AGP                   (1 << 1)
-#define MGA_STATUS                     0x1e14
+#define MGA_STATUS                     0x1e14
 #      define MGA_SOFTRAPEN                    (1 << 0)
 #      define MGA_VSYNCPEN                     (1 << 4)
 #      define MGA_VLINEPEN                     (1 << 5)
 #      define MGA_DWGENGSTS                    (1 << 16)
 #      define MGA_ENDPRDMASTS                  (1 << 17)
 #define MGA_STENCIL                    0x2cc8
-#define MGA_STENCILCTL                         0x2ccc
+#define MGA_STENCILCTL                 0x2ccc
 
-#define MGA_TDUALSTAGE0                0x2cf8
-#define MGA_TDUALSTAGE1                0x2cfc
-#define MGA_TEXBORDERCOL               0x2c5c
-#define MGA_TEXCTL                     0x2c30
+#define MGA_TDUALSTAGE0                        0x2cf8
+#define MGA_TDUALSTAGE1                        0x2cfc
+#define MGA_TEXBORDERCOL               0x2c5c
+#define MGA_TEXCTL                     0x2c30
 #define MGA_TEXCTL2                    0x2c3c
 #      define MGA_DUALTEX                      (1 << 7)
 #      define MGA_G400_TC2_MAGIC               (1 << 15)
 #      define MGA_MAP1_ENABLE                  (1 << 31)
-#define MGA_TEXFILTER                  0x2c58
-#define MGA_TEXHEIGHT                  0x2c2c
-#define MGA_TEXORG                     0x2c24
+#define MGA_TEXFILTER                  0x2c58
+#define MGA_TEXHEIGHT                  0x2c2c
+#define MGA_TEXORG                     0x2c24
 #      define MGA_TEXORGMAP_MASK               (1 << 0)
 #      define MGA_TEXORGMAP_FB                 (0 << 0)
 #      define MGA_TEXORGMAP_SYSMEM             (1 << 0)
@@ -534,45 +533,45 @@ do {                                                                      \
 #define MGA_TEXORG2                    0x2ca8
 #define MGA_TEXORG3                    0x2cac
 #define MGA_TEXORG4                    0x2cb0
-#define MGA_TEXTRANS                   0x2c34
-#define MGA_TEXTRANSHIGH               0x2c38
-#define MGA_TEXWIDTH                   0x2c28
-
-#define MGA_WACCEPTSEQ                         0x1dd4
-#define MGA_WCODEADDR                  0x1e6c
-#define MGA_WFLAG                      0x1dc4
-#define MGA_WFLAG1                     0x1de0
+#define MGA_TEXTRANS                   0x2c34
+#define MGA_TEXTRANSHIGH               0x2c38
+#define MGA_TEXWIDTH                   0x2c28
+
+#define MGA_WACCEPTSEQ                 0x1dd4
+#define MGA_WCODEADDR                  0x1e6c
+#define MGA_WFLAG                      0x1dc4
+#define MGA_WFLAG1                     0x1de0
 #define MGA_WFLAGNB                    0x1e64
-#define MGA_WFLAGNB1                   0x1e08
+#define MGA_WFLAGNB1                   0x1e08
 #define MGA_WGETMSB                    0x1dc8
-#define MGA_WIADDR                     0x1dc0
+#define MGA_WIADDR                     0x1dc0
 #define MGA_WIADDR2                    0x1dd8
 #      define MGA_WMODE_SUSPEND                (0 << 0)
 #      define MGA_WMODE_RESUME                 (1 << 0)
 #      define MGA_WMODE_JUMP                   (2 << 0)
 #      define MGA_WMODE_START                  (3 << 0)
 #      define MGA_WAGP_ENABLE                  (1 << 2)
-#define MGA_WMISC                      0x1e70
+#define MGA_WMISC                      0x1e70
 #      define MGA_WUCODECACHE_ENABLE           (1 << 0)
 #      define MGA_WMASTER_ENABLE               (1 << 1)
 #      define MGA_WCACHEFLUSH_ENABLE           (1 << 3)
 #define MGA_WVRTXSZ                    0x1dcc
 
-#define MGA_YBOT                       0x1c9c
-#define MGA_YDST                       0x1c90
+#define MGA_YBOT                       0x1c9c
+#define MGA_YDST                       0x1c90
 #define MGA_YDSTLEN                    0x1c88
 #define MGA_YDSTORG                    0x1c94
-#define MGA_YTOP                       0x1c98
+#define MGA_YTOP                       0x1c98
 
-#define MGA_ZORG                       0x1c0c
+#define MGA_ZORG                       0x1c0c
 
 /* This finishes the current batch of commands
  */
-#define MGA_EXEC                       0x0100
+#define MGA_EXEC                       0x0100
 
 /* AGP PLL encoding (for G200 only).
  */
-#define MGA_AGP_PLL                    0x1e4c
+#define MGA_AGP_PLL                    0x1e4c
 #      define MGA_AGP2XPLL_DISABLE             (0 << 0)
 #      define MGA_AGP2XPLL_ENABLE              (1 << 0)
 
index 5ec8b61c5d455b29321678e6f504e9b0a329dbfc..d3f8aade07b336be0d6d37d2a1e09913669d5680 100644 (file)
@@ -150,8 +150,8 @@ static __inline__ void mga_g400_emit_tex0(drm_mga_private_t * dev_priv)
        drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
        DMA_LOCALS;
 
-/*     printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */
-/*            tex->texctl, tex->texctl2); */
+/*     printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */
+/*            tex->texctl, tex->texctl2); */
 
        BEGIN_DMA(6);
 
@@ -190,8 +190,8 @@ static __inline__ void mga_g400_emit_tex1(drm_mga_private_t * dev_priv)
        drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1];
        DMA_LOCALS;
 
-/*     printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg,  */
-/*            tex->texctl, tex->texctl2); */
+/*     printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg,  */
+/*            tex->texctl, tex->texctl2); */
 
        BEGIN_DMA(5);
 
@@ -256,7 +256,7 @@ static __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv)
        unsigned int pipe = sarea_priv->warp_pipe;
        DMA_LOCALS;
 
-/*     printk("mga_g400_emit_pipe %x\n", pipe); */
+/*     printk("mga_g400_emit_pipe %x\n", pipe); */
 
        BEGIN_DMA(10);
 
@@ -619,7 +619,7 @@ static void mga_dma_dispatch_swap(struct drm_device * dev)
 
        FLUSH_DMA();
 
-       DRM_DEBUG("%s... done.\n", __FUNCTION__);
+       DRM_DEBUG("... done.\n");
 }
 
 static void mga_dma_dispatch_vertex(struct drm_device * dev, struct drm_buf * buf)
@@ -631,7 +631,7 @@ static void mga_dma_dispatch_vertex(struct drm_device * dev, struct drm_buf * bu
        u32 length = (u32) buf->used;
        int i = 0;
        DMA_LOCALS;
-       DRM_DEBUG("vertex: buf=%d used=%d\n", buf->idx, buf->used);
+       DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used);
 
        if (buf->used) {
                buf_priv->dispatched = 1;
@@ -678,7 +678,7 @@ static void mga_dma_dispatch_indices(struct drm_device * dev, struct drm_buf * b
        u32 address = (u32) buf->bus_address;
        int i = 0;
        DMA_LOCALS;
-       DRM_DEBUG("indices: buf=%d start=%d end=%d\n", buf->idx, start, end);
+       DRM_DEBUG("buf=%d start=%d end=%d\n", buf->idx, start, end);
 
        if (start != end) {
                buf_priv->dispatched = 1;
@@ -955,7 +955,7 @@ static int mga_dma_iload(struct drm_device *dev, void *data, struct drm_file *fi
 #if 0
        if (mga_do_wait_for_idle(dev_priv) < 0) {
                if (MGA_DMA_DEBUG)
-                       DRM_INFO("%s: -EBUSY\n", __FUNCTION__);
+                       DRM_INFO("-EBUSY\n");
                return -EBUSY;
        }
 #endif
@@ -1014,7 +1014,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil
        int value;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -1046,7 +1046,7 @@ static int mga_set_fence(struct drm_device *dev, void *data, struct drm_file *fi
        DMA_LOCALS;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -1075,7 +1075,7 @@ file_priv)
        u32 *fence = data;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
index 7d550aba165e6f7301410b1f2b915c3713fcdd67..892e0a58984669ccbfdce83aba673e23fadb7cb1 100644 (file)
@@ -1,4 +1,4 @@
-/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*- 
+/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
  * Created: Wed Apr  5 19:24:19 2000 by kevin@precisioninsight.com
  */
 /*
@@ -651,7 +651,7 @@ int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_pri
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
-               DRM_DEBUG("%s while CCE running\n", __FUNCTION__);
+               DRM_DEBUG("while CCE running\n");
                return 0;
        }
 
@@ -710,7 +710,7 @@ int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_pri
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
-               DRM_DEBUG("%s called before init done\n", __FUNCTION__);
+               DRM_DEBUG("called before init done\n");
                return -EINVAL;
        }
 
index 5041bd8dbed86b40f719c5d3eac865a7ccf02eaa..011105e51ac660117c88a1e1a3d9db860702b325 100644 (file)
@@ -462,8 +462,7 @@ do {                                                                        \
 
 #define BEGIN_RING( n ) do {                                           \
        if ( R128_VERBOSE ) {                                           \
-               DRM_INFO( "BEGIN_RING( %d ) in %s\n",                   \
-                          (n), __FUNCTION__ );                         \
+               DRM_INFO( "BEGIN_RING( %d )\n", (n));                   \
        }                                                               \
        if ( dev_priv->ring.space <= (n) * sizeof(u32) ) {              \
                COMMIT_RING();                                          \
@@ -493,7 +492,7 @@ do {                                                                        \
                        write * sizeof(u32) );                          \
        }                                                               \
        if (((dev_priv->ring.tail + _nr) & tail_mask) != write) {       \
-               DRM_ERROR(                                              \
+               DRM_ERROR(                                              \
                        "ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n",        \
                        ((dev_priv->ring.tail + _nr) & tail_mask),      \
                        write, __LINE__);                               \
index b7f483cac6d4b7973f1627912cee23235485af54..51a9afce7b9b9b5e9a9a965fc8091078d3edca05 100644 (file)
@@ -42,7 +42,7 @@ static void r128_emit_clip_rects(drm_r128_private_t * dev_priv,
 {
        u32 aux_sc_cntl = 0x00000000;
        RING_LOCALS;
-       DRM_DEBUG("    %s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        BEGIN_RING((count < 3 ? count : 3) * 5 + 2);
 
@@ -85,7 +85,7 @@ static __inline__ void r128_emit_core(drm_r128_private_t * dev_priv)
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
        drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
        RING_LOCALS;
-       DRM_DEBUG("    %s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        BEGIN_RING(2);
 
@@ -100,7 +100,7 @@ static __inline__ void r128_emit_context(drm_r128_private_t * dev_priv)
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
        drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
        RING_LOCALS;
-       DRM_DEBUG("    %s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        BEGIN_RING(13);
 
@@ -126,7 +126,7 @@ static __inline__ void r128_emit_setup(drm_r128_private_t * dev_priv)
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
        drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
        RING_LOCALS;
-       DRM_DEBUG("    %s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        BEGIN_RING(3);
 
@@ -142,7 +142,7 @@ static __inline__ void r128_emit_masks(drm_r128_private_t * dev_priv)
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
        drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
        RING_LOCALS;
-       DRM_DEBUG("    %s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        BEGIN_RING(5);
 
@@ -161,7 +161,7 @@ static __inline__ void r128_emit_window(drm_r128_private_t * dev_priv)
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
        drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
        RING_LOCALS;
-       DRM_DEBUG("    %s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        BEGIN_RING(2);
 
@@ -178,7 +178,7 @@ static __inline__ void r128_emit_tex0(drm_r128_private_t * dev_priv)
        drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[0];
        int i;
        RING_LOCALS;
-       DRM_DEBUG("    %s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        BEGIN_RING(7 + R128_MAX_TEXTURE_LEVELS);
 
@@ -204,7 +204,7 @@ static __inline__ void r128_emit_tex1(drm_r128_private_t * dev_priv)
        drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1];
        int i;
        RING_LOCALS;
-       DRM_DEBUG("    %s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        BEGIN_RING(5 + R128_MAX_TEXTURE_LEVELS);
 
@@ -226,7 +226,7 @@ static void r128_emit_state(drm_r128_private_t * dev_priv)
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
        unsigned int dirty = sarea_priv->dirty;
 
-       DRM_DEBUG("%s: dirty=0x%08x\n", __FUNCTION__, dirty);
+       DRM_DEBUG("dirty=0x%08x\n", dirty);
 
        if (dirty & R128_UPLOAD_CORE) {
                r128_emit_core(dev_priv);
@@ -362,7 +362,7 @@ static void r128_cce_dispatch_clear(struct drm_device * dev,
        unsigned int flags = clear->flags;
        int i;
        RING_LOCALS;
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        if (dev_priv->page_flipping && dev_priv->current_page == 1) {
                unsigned int tmp = flags;
@@ -466,7 +466,7 @@ static void r128_cce_dispatch_swap(struct drm_device * dev)
        struct drm_clip_rect *pbox = sarea_priv->boxes;
        int i;
        RING_LOCALS;
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
 #if R128_PERFORMANCE_BOXES
        /* Do some trivial performance monitoring...
@@ -528,8 +528,7 @@ static void r128_cce_dispatch_flip(struct drm_device * dev)
 {
        drm_r128_private_t *dev_priv = dev->dev_private;
        RING_LOCALS;
-       DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
-                 __FUNCTION__,
+       DRM_DEBUG("page=%d pfCurrentPage=%d\n",
                  dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
 
 #if R128_PERFORMANCE_BOXES
@@ -1156,7 +1155,7 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
        int count, *x, *y;
        int i, xbuf_size, ybuf_size;
        RING_LOCALS;
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        count = depth->n;
        if (count > 4096 || count <= 0)
@@ -1226,7 +1225,7 @@ static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple)
        drm_r128_private_t *dev_priv = dev->dev_private;
        int i;
        RING_LOCALS;
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        BEGIN_RING(33);
 
@@ -1309,7 +1308,7 @@ static int r128_do_cleanup_pageflip(struct drm_device * dev)
 static int r128_cce_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        drm_r128_private_t *dev_priv = dev->dev_private;
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -1328,7 +1327,7 @@ static int r128_cce_swap(struct drm_device *dev, void *data, struct drm_file *fi
 {
        drm_r128_private_t *dev_priv = dev->dev_private;
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -1356,7 +1355,7 @@ static int r128_cce_vertex(struct drm_device *dev, void *data, struct drm_file *
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -1412,7 +1411,7 @@ static int r128_cce_indices(struct drm_device *dev, void *data, struct drm_file
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -1557,11 +1556,11 @@ static int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
-       DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
+       DRM_DEBUG("idx=%d s=%d e=%d d=%d\n",
                  indirect->idx, indirect->start, indirect->end,
                  indirect->discard);
 
@@ -1622,7 +1621,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi
        int value;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
index 59b2944811c50c7c9e0269585ba525ce88a49a4e..0f4afc44245c60ffc9e67cce44aaf209ce58a7a7 100644 (file)
@@ -77,23 +77,31 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
                                return -EFAULT;
                        }
 
-                       box.x1 =
-                           (box.x1 +
-                            R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
-                       box.y1 =
-                           (box.y1 +
-                            R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
-                       box.x2 =
-                           (box.x2 +
-                            R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
-                       box.y2 =
-                           (box.y2 +
-                            R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
+                       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
+                               box.x1 = (box.x1) &
+                                       R300_CLIPRECT_MASK;
+                               box.y1 = (box.y1) &
+                                       R300_CLIPRECT_MASK;
+                               box.x2 = (box.x2) &
+                                       R300_CLIPRECT_MASK;
+                               box.y2 = (box.y2) &
+                                       R300_CLIPRECT_MASK;
+                       } else {
+                               box.x1 = (box.x1 + R300_CLIPRECT_OFFSET) &
+                                       R300_CLIPRECT_MASK;
+                               box.y1 = (box.y1 + R300_CLIPRECT_OFFSET) &
+                                       R300_CLIPRECT_MASK;
+                               box.x2 = (box.x2 + R300_CLIPRECT_OFFSET) &
+                                       R300_CLIPRECT_MASK;
+                               box.y2 = (box.y2 + R300_CLIPRECT_OFFSET) &
+                                       R300_CLIPRECT_MASK;
 
+                       }
                        OUT_RING((box.x1 << R300_CLIPRECT_X_SHIFT) |
                                 (box.y1 << R300_CLIPRECT_Y_SHIFT));
                        OUT_RING((box.x2 << R300_CLIPRECT_X_SHIFT) |
                                 (box.y2 << R300_CLIPRECT_Y_SHIFT));
+
                }
 
                OUT_RING_REG(R300_RE_CLIPRECT_CNTL, r300_cliprect_cntl[nr - 1]);
@@ -133,9 +141,11 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
 
 static u8 r300_reg_flags[0x10000 >> 2];
 
-void r300_init_reg_flags(void)
+void r300_init_reg_flags(struct drm_device *dev)
 {
        int i;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
        memset(r300_reg_flags, 0, 0x10000 >> 2);
 #define ADD_RANGE_MARK(reg, count,mark) \
                for(i=((reg)>>2);i<((reg)>>2)+(count);i++)\
@@ -230,6 +240,9 @@ void r300_init_reg_flags(void)
        ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8);
        ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8);
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
+               ADD_RANGE(0x4074, 16);
+       }
 }
 
 static __inline__ int r300_check_range(unsigned reg, int count)
@@ -486,7 +499,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
        if (cmd[0] & 0x8000) {
                u32 offset;
 
-               if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL 
+               if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
                              | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
                        offset = cmd[2] << 10;
                        ret = !radeon_check_offset(dev_priv, offset);
@@ -504,7 +517,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
                                DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
                                return -EINVAL;
                        }
-                       
+
                }
        }
 
@@ -723,54 +736,54 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
        u32 *ref_age_base;
        u32 i, buf_idx, h_pending;
        RING_LOCALS;
-       
-       if (cmdbuf->bufsz < 
+
+       if (cmdbuf->bufsz <
            (sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) {
                return -EINVAL;
        }
-       
+
        if (header.scratch.reg >= 5) {
                return -EINVAL;
        }
-       
+
        dev_priv->scratch_ages[header.scratch.reg]++;
-       
+
        ref_age_base =  (u32 *)(unsigned long)*((uint64_t *)cmdbuf->buf);
-       
+
        cmdbuf->buf += sizeof(u64);
        cmdbuf->bufsz -= sizeof(u64);
-       
+
        for (i=0; i < header.scratch.n_bufs; i++) {
                buf_idx = *(u32 *)cmdbuf->buf;
                buf_idx *= 2; /* 8 bytes per buf */
-               
+
                if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
                        return -EINVAL;
                }
-                                       
+
                if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
                        return -EINVAL;
                }
-                                       
+
                if (h_pending == 0) {
                        return -EINVAL;
                }
-                                       
+
                h_pending--;
-                                               
+
                if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
                        return -EINVAL;
                }
-                                       
+
                cmdbuf->buf += sizeof(buf_idx);
                cmdbuf->bufsz -= sizeof(buf_idx);
        }
-       
+
        BEGIN_RING(2);
        OUT_RING( CP_PACKET0( RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0 ) );
        OUT_RING( dev_priv->scratch_ages[header.scratch.reg] );
        ADVANCE_RING();
-       
+
        return 0;
 }
 
@@ -919,7 +932,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
                                goto cleanup;
                        }
                        break;
-                       
+
                default:
                        DRM_ERROR("bad cmd_type %i at %p\n",
                                  header.header.cmd_type,
index fa194a46c1e4f3166ef0d2164e215b8221b9be07..8f664af9c4a4f50d7ecd905b81fa39dd15dde89f 100644 (file)
@@ -853,13 +853,13 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #      define R300_TX_FORMAT_W8Z8Y8X8              0xC
 #      define R300_TX_FORMAT_W2Z10Y10X10           0xD
 #      define R300_TX_FORMAT_W16Z16Y16X16          0xE
-#      define R300_TX_FORMAT_DXT1                  0xF
-#      define R300_TX_FORMAT_DXT3                  0x10
-#      define R300_TX_FORMAT_DXT5                  0x11
+#      define R300_TX_FORMAT_DXT1                  0xF
+#      define R300_TX_FORMAT_DXT3                  0x10
+#      define R300_TX_FORMAT_DXT5                  0x11
 #      define R300_TX_FORMAT_D3DMFT_CxV8U8         0x12     /* no swizzle */
-#      define R300_TX_FORMAT_A8R8G8B8              0x13     /* no swizzle */
-#      define R300_TX_FORMAT_B8G8_B8G8             0x14     /* no swizzle */
-#      define R300_TX_FORMAT_G8R8_G8B8             0x15     /* no swizzle */
+#      define R300_TX_FORMAT_A8R8G8B8              0x13     /* no swizzle */
+#      define R300_TX_FORMAT_B8G8_B8G8             0x14     /* no swizzle */
+#      define R300_TX_FORMAT_G8R8_G8B8             0x15     /* no swizzle */
        /* 0x16 - some 16 bit green format.. ?? */
 #      define R300_TX_FORMAT_UNK25                (1 << 25) /* no swizzle */
 #      define R300_TX_FORMAT_CUBIC_MAP            (1 << 26)
@@ -867,19 +867,19 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
        /* gap */
        /* Floating point formats */
        /* Note - hardware supports both 16 and 32 bit floating point */
-#      define R300_TX_FORMAT_FL_I16                0x18
-#      define R300_TX_FORMAT_FL_I16A16             0x19
+#      define R300_TX_FORMAT_FL_I16                0x18
+#      define R300_TX_FORMAT_FL_I16A16             0x19
 #      define R300_TX_FORMAT_FL_R16G16B16A16       0x1A
-#      define R300_TX_FORMAT_FL_I32                0x1B
-#      define R300_TX_FORMAT_FL_I32A32             0x1C
+#      define R300_TX_FORMAT_FL_I32                0x1B
+#      define R300_TX_FORMAT_FL_I32A32             0x1C
 #      define R300_TX_FORMAT_FL_R32G32B32A32       0x1D
        /* alpha modes, convenience mostly */
        /* if you have alpha, pick constant appropriate to the
           number of channels (1 for I8, 2 for I8A8, 4 for R8G8B8A8, etc */
-#      define R300_TX_FORMAT_ALPHA_1CH             0x000
-#      define R300_TX_FORMAT_ALPHA_2CH             0x200
-#      define R300_TX_FORMAT_ALPHA_4CH             0x600
-#      define R300_TX_FORMAT_ALPHA_NONE            0xA00
+#      define R300_TX_FORMAT_ALPHA_1CH             0x000
+#      define R300_TX_FORMAT_ALPHA_2CH             0x200
+#      define R300_TX_FORMAT_ALPHA_4CH             0x600
+#      define R300_TX_FORMAT_ALPHA_NONE            0xA00
        /* Swizzling */
        /* constants */
 #      define R300_TX_FORMAT_X         0
@@ -1360,11 +1360,11 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #       define R300_RB3D_Z_DISABLED_2            0x00000014
 #       define R300_RB3D_Z_TEST                  0x00000012
 #       define R300_RB3D_Z_TEST_AND_WRITE        0x00000016
-#       define R300_RB3D_Z_WRITE_ONLY           0x00000006
+#       define R300_RB3D_Z_WRITE_ONLY           0x00000006
 
 #       define R300_RB3D_Z_TEST                  0x00000012
 #       define R300_RB3D_Z_TEST_AND_WRITE        0x00000016
-#       define R300_RB3D_Z_WRITE_ONLY           0x00000006
+#       define R300_RB3D_Z_WRITE_ONLY           0x00000006
 #      define R300_RB3D_STENCIL_ENABLE          0x00000001
 
 #define R300_RB3D_ZSTENCIL_CNTL_1                   0x4F04
index 24fca8ec137957524240bbf018a0ff3374e29c03..5dc799ab86b8b9ac2bcbe54878987308e3df3dc7 100644 (file)
@@ -816,6 +816,46 @@ static const u32 R300_cp_microcode[][2] = {
        {0000000000, 0000000000},
 };
 
+static u32 RADEON_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+{
+       u32 ret;
+       RADEON_WRITE(R520_MC_IND_INDEX, 0x7f0000 | (addr & 0xff));
+       ret = RADEON_READ(R520_MC_IND_DATA);
+       RADEON_WRITE(R520_MC_IND_INDEX, 0);
+       return ret;
+}
+
+u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
+{
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
+               return RADEON_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
+               return RADEON_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
+       else
+               return RADEON_READ(RADEON_MC_FB_LOCATION);
+}
+
+static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
+{
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
+               RADEON_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
+               RADEON_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
+       else
+               RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc);
+}
+
+static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
+{
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
+               RADEON_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
+               RADEON_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
+       else
+               RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_loc);
+}
+
 static int RADEON_READ_PLL(struct drm_device * dev, int addr)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -824,7 +864,7 @@ static int RADEON_READ_PLL(struct drm_device * dev, int addr)
        return RADEON_READ(RADEON_CLOCK_CNTL_DATA);
 }
 
-static int RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr)
+static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr)
 {
        RADEON_WRITE8(RADEON_PCIE_INDEX, addr & 0xff);
        return RADEON_READ(RADEON_PCIE_DATA);
@@ -1074,41 +1114,43 @@ static int radeon_do_engine_reset(struct drm_device * dev)
 
        radeon_do_pixcache_flush(dev_priv);
 
-       clock_cntl_index = RADEON_READ(RADEON_CLOCK_CNTL_INDEX);
-       mclk_cntl = RADEON_READ_PLL(dev, RADEON_MCLK_CNTL);
-
-       RADEON_WRITE_PLL(RADEON_MCLK_CNTL, (mclk_cntl |
-                                           RADEON_FORCEON_MCLKA |
-                                           RADEON_FORCEON_MCLKB |
-                                           RADEON_FORCEON_YCLKA |
-                                           RADEON_FORCEON_YCLKB |
-                                           RADEON_FORCEON_MC |
-                                           RADEON_FORCEON_AIC));
-
-       rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET);
-
-       RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
-                                             RADEON_SOFT_RESET_CP |
-                                             RADEON_SOFT_RESET_HI |
-                                             RADEON_SOFT_RESET_SE |
-                                             RADEON_SOFT_RESET_RE |
-                                             RADEON_SOFT_RESET_PP |
-                                             RADEON_SOFT_RESET_E2 |
-                                             RADEON_SOFT_RESET_RB));
-       RADEON_READ(RADEON_RBBM_SOFT_RESET);
-       RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
-                                             ~(RADEON_SOFT_RESET_CP |
-                                               RADEON_SOFT_RESET_HI |
-                                               RADEON_SOFT_RESET_SE |
-                                               RADEON_SOFT_RESET_RE |
-                                               RADEON_SOFT_RESET_PP |
-                                               RADEON_SOFT_RESET_E2 |
-                                               RADEON_SOFT_RESET_RB)));
-       RADEON_READ(RADEON_RBBM_SOFT_RESET);
-
-       RADEON_WRITE_PLL(RADEON_MCLK_CNTL, mclk_cntl);
-       RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index);
-       RADEON_WRITE(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV515) {
+               clock_cntl_index = RADEON_READ(RADEON_CLOCK_CNTL_INDEX);
+               mclk_cntl = RADEON_READ_PLL(dev, RADEON_MCLK_CNTL);
+
+               RADEON_WRITE_PLL(RADEON_MCLK_CNTL, (mclk_cntl |
+                                                   RADEON_FORCEON_MCLKA |
+                                                   RADEON_FORCEON_MCLKB |
+                                                   RADEON_FORCEON_YCLKA |
+                                                   RADEON_FORCEON_YCLKB |
+                                                   RADEON_FORCEON_MC |
+                                                   RADEON_FORCEON_AIC));
+
+               rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET);
+
+               RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
+                                                     RADEON_SOFT_RESET_CP |
+                                                     RADEON_SOFT_RESET_HI |
+                                                     RADEON_SOFT_RESET_SE |
+                                                     RADEON_SOFT_RESET_RE |
+                                                     RADEON_SOFT_RESET_PP |
+                                                     RADEON_SOFT_RESET_E2 |
+                                                     RADEON_SOFT_RESET_RB));
+               RADEON_READ(RADEON_RBBM_SOFT_RESET);
+               RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
+                                                     ~(RADEON_SOFT_RESET_CP |
+                                                       RADEON_SOFT_RESET_HI |
+                                                       RADEON_SOFT_RESET_SE |
+                                                       RADEON_SOFT_RESET_RE |
+                                                       RADEON_SOFT_RESET_PP |
+                                                       RADEON_SOFT_RESET_E2 |
+                                                       RADEON_SOFT_RESET_RB)));
+               RADEON_READ(RADEON_RBBM_SOFT_RESET);
+
+               RADEON_WRITE_PLL(RADEON_MCLK_CNTL, mclk_cntl);
+               RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index);
+               RADEON_WRITE(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
+       }
 
        /* Reset the CP ring */
        radeon_do_cp_reset(dev_priv);
@@ -1127,21 +1169,21 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
 {
        u32 ring_start, cur_read_ptr;
        u32 tmp;
-       
+
        /* Initialize the memory controller. With new memory map, the fb location
         * is not changed, it should have been properly initialized already. Part
         * of the problem is that the code below is bogus, assuming the GART is
         * always appended to the fb which is not necessarily the case
         */
        if (!dev_priv->new_memmap)
-               RADEON_WRITE(RADEON_MC_FB_LOCATION,
+               radeon_write_fb_location(dev_priv,
                             ((dev_priv->gart_vm_start - 1) & 0xffff0000)
                             | (dev_priv->fb_location >> 16));
 
 #if __OS_HAS_AGP
        if (dev_priv->flags & RADEON_IS_AGP) {
                RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
-               RADEON_WRITE(RADEON_MC_AGP_LOCATION,
+               radeon_write_agp_location(dev_priv,
                             (((dev_priv->gart_vm_start - 1 +
                                dev_priv->gart_size) & 0xffff0000) |
                              (dev_priv->gart_vm_start >> 16)));
@@ -1190,9 +1232,15 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
        /* Set ring buffer size */
 #ifdef __BIG_ENDIAN
        RADEON_WRITE(RADEON_CP_RB_CNTL,
-                    dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT);
+                    RADEON_BUF_SWAP_32BIT |
+                    (dev_priv->ring.fetch_size_l2ow << 18) |
+                    (dev_priv->ring.rptr_update_l2qw << 8) |
+                    dev_priv->ring.size_l2qw);
 #else
-       RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw);
+       RADEON_WRITE(RADEON_CP_RB_CNTL,
+                    (dev_priv->ring.fetch_size_l2ow << 18) |
+                    (dev_priv->ring.rptr_update_l2qw << 8) |
+                    dev_priv->ring.size_l2qw);
 #endif
 
        /* Start with assuming that writeback doesn't work */
@@ -1299,7 +1347,7 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
 
                RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start);
                dev_priv->gart_size = 32*1024*1024;
-               RADEON_WRITE(RADEON_MC_AGP_LOCATION,
+               radeon_write_agp_location(dev_priv,
                             (((dev_priv->gart_vm_start - 1 +
                               dev_priv->gart_size) & 0xffff0000) |
                             (dev_priv->gart_vm_start >> 16)));
@@ -1333,7 +1381,7 @@ static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
                                  dev_priv->gart_vm_start +
                                  dev_priv->gart_size - 1);
 
-               RADEON_WRITE(RADEON_MC_AGP_LOCATION, 0xffffffc0);       /* ?? */
+               radeon_write_agp_location(dev_priv, 0xffffffc0); /* ?? */
 
                RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
                                  RADEON_PCIE_TX_GART_EN);
@@ -1358,7 +1406,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
                return;
        }
 
-       tmp = RADEON_READ(RADEON_AIC_CNTL);
+       tmp = RADEON_READ(RADEON_AIC_CNTL);
 
        if (on) {
                RADEON_WRITE(RADEON_AIC_CNTL,
@@ -1376,7 +1424,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
 
                /* Turn off AGP aperture -- is this required for PCI GART?
                 */
-               RADEON_WRITE(RADEON_MC_AGP_LOCATION, 0xffffffc0);       /* ?? */
+               radeon_write_agp_location(dev_priv, 0xffffffc0);
                RADEON_WRITE(RADEON_AGP_COMMAND, 0);    /* clear AGP_COMMAND */
        } else {
                RADEON_WRITE(RADEON_AIC_CNTL,
@@ -1581,10 +1629,9 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
                          dev->agp_buffer_map->handle);
        }
 
-       dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION)
-                                & 0xffff) << 16;
-       dev_priv->fb_size = 
-               ((RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff0000u) + 0x10000)
+       dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16;
+       dev_priv->fb_size =
+               ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000)
                - dev_priv->fb_location;
 
        dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
@@ -1630,7 +1677,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
                            ((base + dev_priv->gart_size) & 0xfffffffful) < base)
                                base = dev_priv->fb_location
                                        - dev_priv->gart_size;
-               }               
+               }
                dev_priv->gart_vm_start = base & 0xffc00000u;
                if (dev_priv->gart_vm_start != base)
                        DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n",
@@ -1663,6 +1710,11 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
        dev_priv->ring.size = init->ring_size;
        dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
 
+       dev_priv->ring.rptr_update = /* init->rptr_update */ 4096;
+       dev_priv->ring.rptr_update_l2qw = drm_order( /* init->rptr_update */ 4096 / 8);
+
+       dev_priv->ring.fetch_size = /* init->fetch_size */ 32;
+       dev_priv->ring.fetch_size_l2ow = drm_order( /* init->fetch_size */ 32 / 16);
        dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
 
        dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
@@ -1830,7 +1882,7 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (init->func == RADEON_INIT_R300_CP)
-               r300_init_reg_flags();
+               r300_init_reg_flags(dev);
 
        switch (init->func) {
        case RADEON_INIT_CP:
@@ -1852,12 +1904,12 @@ int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_pr
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (dev_priv->cp_running) {
-               DRM_DEBUG("%s while CP running\n", __FUNCTION__);
+               DRM_DEBUG("while CP running\n");
                return 0;
        }
        if (dev_priv->cp_mode == RADEON_CSQ_PRIDIS_INDDIS) {
-               DRM_DEBUG("%s called with bogus CP mode (%d)\n",
-                         __FUNCTION__, dev_priv->cp_mode);
+               DRM_DEBUG("called with bogus CP mode (%d)\n",
+                         dev_priv->cp_mode);
                return 0;
        }
 
@@ -1962,7 +2014,7 @@ int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_pr
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
-               DRM_DEBUG("%s called before init done\n", __FUNCTION__);
+               DRM_DEBUG("called before init done\n");
                return -EINVAL;
        }
 
@@ -2239,6 +2291,10 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
        case CHIP_R350:
        case CHIP_R420:
        case CHIP_RV410:
+       case CHIP_RV515:
+       case CHIP_R520:
+       case CHIP_RV570:
+       case CHIP_R580:
                dev_priv->flags |= RADEON_HAS_HIERZ;
                break;
        default:
index 5a8e23f916fc192f05e9c52980d9ef8a5baaff48..71e5b21fad2c3c8cb99ee57630c30bad5ac0bd63 100644 (file)
@@ -223,10 +223,10 @@ typedef union {
 #define R300_CMD_CP_DELAY              5
 #define R300_CMD_DMA_DISCARD           6
 #define R300_CMD_WAIT                  7
-#      define R300_WAIT_2D             0x1
-#      define R300_WAIT_3D             0x2
-#      define R300_WAIT_2D_CLEAN       0x3
-#      define R300_WAIT_3D_CLEAN       0x4
+#      define R300_WAIT_2D             0x1
+#      define R300_WAIT_3D             0x2
+#      define R300_WAIT_2D_CLEAN       0x3
+#      define R300_WAIT_3D_CLEAN       0x4
 #define R300_CMD_SCRATCH               8
 
 typedef union {
@@ -656,6 +656,7 @@ typedef struct drm_radeon_indirect {
 #define RADEON_PARAM_SCRATCH_OFFSET        11
 #define RADEON_PARAM_CARD_TYPE             12
 #define RADEON_PARAM_VBLANK_CRTC           13   /* VBLANK CRTC */
+#define RADEON_PARAM_FB_LOCATION           14   /* FB location */
 
 typedef struct drm_radeon_getparam {
        int param;
@@ -722,7 +723,7 @@ typedef struct drm_radeon_surface_free {
        unsigned int address;
 } drm_radeon_surface_free_t;
 
-#define        DRM_RADEON_VBLANK_CRTC1         1
-#define        DRM_RADEON_VBLANK_CRTC2         2
+#define        DRM_RADEON_VBLANK_CRTC1         1
+#define        DRM_RADEON_VBLANK_CRTC2         2
 
 #endif
index bfbb60a9298ca7d57e0ad030751fe61799ccc73e..4434332c79bcc9115591297a8c7248f5f6c4fb4c 100644 (file)
@@ -123,6 +123,12 @@ enum radeon_family {
        CHIP_R420,
        CHIP_RV410,
        CHIP_RS400,
+       CHIP_RV515,
+       CHIP_R520,
+       CHIP_RV530,
+       CHIP_RV560,
+       CHIP_RV570,
+       CHIP_R580,
        CHIP_LAST,
 };
 
@@ -166,6 +172,12 @@ typedef struct drm_radeon_ring_buffer {
        int size;
        int size_l2qw;
 
+       int rptr_update; /* Double Words */
+       int rptr_update_l2qw; /* log2 Quad Words */
+
+       int fetch_size; /* Double Words */
+       int fetch_size_l2ow; /* log2 Oct Words */
+
        u32 tail;
        u32 tail_mask;
        int space;
@@ -336,6 +348,7 @@ extern int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file
 extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv);
 
 extern void radeon_freelist_reset(struct drm_device * dev);
 extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);
@@ -382,7 +395,7 @@ extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
                                unsigned long arg);
 
 /* r300_cmdbuf.c */
-extern void r300_init_reg_flags(void);
+extern void r300_init_reg_flags(struct drm_device *dev);
 
 extern int r300_do_cp_cmdbuf(struct drm_device * dev,
                             struct drm_file *file_priv,
@@ -429,7 +442,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
 #define RADEON_PCIE_INDEX               0x0030
 #define RADEON_PCIE_DATA                0x0034
 #define RADEON_PCIE_TX_GART_CNTL       0x10
-#      define RADEON_PCIE_TX_GART_EN           (1 << 0)
+#      define RADEON_PCIE_TX_GART_EN           (1 << 0)
 #      define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_PASS_THRU (0<<1)
 #      define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_CLAMP_LO  (1<<1)
 #      define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD   (3<<1)
@@ -439,7 +452,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
 #      define RADEON_PCIE_TX_GART_INVALIDATE_TLB       (1<<8)
 #define RADEON_PCIE_TX_DISCARD_RD_ADDR_LO 0x11
 #define RADEON_PCIE_TX_DISCARD_RD_ADDR_HI 0x12
-#define RADEON_PCIE_TX_GART_BASE       0x13
+#define RADEON_PCIE_TX_GART_BASE       0x13
 #define RADEON_PCIE_TX_GART_START_LO   0x14
 #define RADEON_PCIE_TX_GART_START_HI   0x15
 #define RADEON_PCIE_TX_GART_END_LO     0x16
@@ -454,6 +467,16 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
 #define RADEON_IGPGART_ENABLE           0x38
 #define RADEON_IGPGART_UNK_39           0x39
 
+#define R520_MC_IND_INDEX 0x70
+#define R520_MC_IND_WR_EN (1<<24)
+#define R520_MC_IND_DATA  0x74
+
+#define RV515_MC_FB_LOCATION 0x01
+#define RV515_MC_AGP_LOCATION 0x02
+
+#define R520_MC_FB_LOCATION 0x04
+#define R520_MC_AGP_LOCATION 0x05
+
 #define RADEON_MPP_TB_CONFIG           0x01c0
 #define RADEON_MEM_CNTL                        0x0140
 #define RADEON_MEM_SDRAM_MODE_REG      0x0158
@@ -512,12 +535,12 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
 
 #define RADEON_GEN_INT_STATUS          0x0044
 #      define RADEON_CRTC_VBLANK_STAT          (1 << 0)
-#      define RADEON_CRTC_VBLANK_STAT_ACK      (1 << 0)
+#      define RADEON_CRTC_VBLANK_STAT_ACK      (1 << 0)
 #      define RADEON_CRTC2_VBLANK_STAT         (1 << 9)
-#      define RADEON_CRTC2_VBLANK_STAT_ACK     (1 << 9)
+#      define RADEON_CRTC2_VBLANK_STAT_ACK     (1 << 9)
 #      define RADEON_GUI_IDLE_INT_TEST_ACK     (1 << 19)
 #      define RADEON_SW_INT_TEST               (1 << 25)
-#      define RADEON_SW_INT_TEST_ACK           (1 << 25)
+#      define RADEON_SW_INT_TEST_ACK           (1 << 25)
 #      define RADEON_SW_INT_FIRE               (1 << 26)
 
 #define RADEON_HOST_PATH_CNTL          0x0130
@@ -615,9 +638,51 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
 #      define RADEON_SOFT_RESET_E2             (1 <<  5)
 #      define RADEON_SOFT_RESET_RB             (1 <<  6)
 #      define RADEON_SOFT_RESET_HDP            (1 <<  7)
+/*
+ *   6:0  Available slots in the FIFO
+ *   8    Host Interface active
+ *   9    CP request active
+ *   10   FIFO request active
+ *   11   Host Interface retry active
+ *   12   CP retry active
+ *   13   FIFO retry active
+ *   14   FIFO pipeline busy
+ *   15   Event engine busy
+ *   16   CP command stream busy
+ *   17   2D engine busy
+ *   18   2D portion of render backend busy
+ *   20   3D setup engine busy
+ *   26   GA engine busy
+ *   27   CBA 2D engine busy
+ *   31   2D engine busy or 3D engine busy or FIFO not empty or CP busy or
+ *           command stream queue not empty or Ring Buffer not empty
+ */
 #define RADEON_RBBM_STATUS             0x0e40
+/* Same as the previous RADEON_RBBM_STATUS; this is a mirror of that register.  */
+/* #define RADEON_RBBM_STATUS          0x1740 */
+/* bits 6:0 are dword slots available in the cmd fifo */
 #      define RADEON_RBBM_FIFOCNT_MASK         0x007f
-#      define RADEON_RBBM_ACTIVE               (1 << 31)
+#      define RADEON_HIRQ_ON_RBB       (1 <<  8)
+#      define RADEON_CPRQ_ON_RBB       (1 <<  9)
+#      define RADEON_CFRQ_ON_RBB       (1 << 10)
+#      define RADEON_HIRQ_IN_RTBUF     (1 << 11)
+#      define RADEON_CPRQ_IN_RTBUF     (1 << 12)
+#      define RADEON_CFRQ_IN_RTBUF     (1 << 13)
+#      define RADEON_PIPE_BUSY         (1 << 14)
+#      define RADEON_ENG_EV_BUSY       (1 << 15)
+#      define RADEON_CP_CMDSTRM_BUSY   (1 << 16)
+#      define RADEON_E2_BUSY           (1 << 17)
+#      define RADEON_RB2D_BUSY         (1 << 18)
+#      define RADEON_RB3D_BUSY         (1 << 19) /* not used on r300 */
+#      define RADEON_VAP_BUSY          (1 << 20)
+#      define RADEON_RE_BUSY           (1 << 21) /* not used on r300 */
+#      define RADEON_TAM_BUSY          (1 << 22) /* not used on r300 */
+#      define RADEON_TDM_BUSY          (1 << 23) /* not used on r300 */
+#      define RADEON_PB_BUSY           (1 << 24) /* not used on r300 */
+#      define RADEON_TIM_BUSY          (1 << 25) /* not used on r300 */
+#      define RADEON_GA_BUSY           (1 << 26)
+#      define RADEON_CBA2D_BUSY        (1 << 27)
+#      define RADEON_RBBM_ACTIVE       (1 << 31)
 #define RADEON_RE_LINE_PATTERN         0x1cd0
 #define RADEON_RE_MISC                 0x26c4
 #define RADEON_RE_TOP_LEFT             0x26c0
@@ -1004,6 +1069,13 @@ do {                                                                     \
        RADEON_WRITE( RADEON_PCIE_DATA, (val) );                        \
 } while (0)
 
+#define RADEON_WRITE_MCIND( addr, val )                                        \
+       do {                                                            \
+               RADEON_WRITE(R520_MC_IND_INDEX, 0xff0000 | ((addr) & 0xff));    \
+               RADEON_WRITE(R520_MC_IND_DATA, (val));                  \
+               RADEON_WRITE(R520_MC_IND_INDEX, 0);     \
+       } while (0)
+
 #define CP_PACKET0( reg, n )                                           \
        (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
 #define CP_PACKET0_TABLE( reg, n )                                     \
@@ -1114,8 +1186,7 @@ do {                                                                      \
 
 #define BEGIN_RING( n ) do {                                           \
        if ( RADEON_VERBOSE ) {                                         \
-               DRM_INFO( "BEGIN_RING( %d ) in %s\n",                   \
-                          n, __FUNCTION__ );                           \
+               DRM_INFO( "BEGIN_RING( %d )\n", (n));                   \
        }                                                               \
        if ( dev_priv->ring.space <= (n) * sizeof(u32) ) {              \
                 COMMIT_RING();                                         \
@@ -1133,7 +1204,7 @@ do {                                                                      \
                          write, dev_priv->ring.tail );                 \
        }                                                               \
        if (((dev_priv->ring.tail + _nr) & mask) != write) {            \
-               DRM_ERROR(                                              \
+               DRM_ERROR(                                              \
                        "ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n",        \
                        ((dev_priv->ring.tail + _nr) & mask),           \
                        write, __LINE__);                                               \
index 84f5bc36252b92d8cbaf6fc9a5a4a00ee835f463..009af3814b6f12ec4dcf34aff23cffff79e0d5db 100644 (file)
@@ -154,7 +154,7 @@ static int radeon_driver_vblank_do_wait(struct drm_device * dev,
        int ack = 0;
        atomic_t *counter;
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -205,7 +205,7 @@ int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_pr
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -227,7 +227,7 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr
        drm_radeon_irq_wait_t *irqwait = data;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
index a29acfe2f973c970a3dfbf7600fd7530582fd53d..78b34fa7c89a913e0cd5df3e021e65d713fe3f29 100644 (file)
@@ -224,7 +224,7 @@ int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_p
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -259,7 +259,7 @@ int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_pr
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -285,7 +285,7 @@ int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *fi
        struct mem_block **heap;
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
index f824f2f5fdc29d4474c2da6c57dedf27456e8809..6f75512f591e1b3792025f38491da2e7e3e043ae 100644 (file)
@@ -898,7 +898,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
                        int w = pbox[i].x2 - x;
                        int h = pbox[i].y2 - y;
 
-                       DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
+                       DRM_DEBUG("%d,%d-%d,%d flags 0x%x\n",
                                  x, y, w, h, flags);
 
                        if (flags & RADEON_FRONT) {
@@ -1368,7 +1368,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev)
                int w = pbox[i].x2 - x;
                int h = pbox[i].y2 - y;
 
-               DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
+               DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h);
 
                BEGIN_RING(9);
 
@@ -1422,8 +1422,7 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev)
        int offset = (dev_priv->sarea_priv->pfCurrentPage == 1)
            ? dev_priv->front_offset : dev_priv->back_offset;
        RING_LOCALS;
-       DRM_DEBUG("%s: pfCurrentPage=%d\n",
-                 __FUNCTION__,
+       DRM_DEBUG("pfCurrentPage=%d\n",
                  dev_priv->sarea_priv->pfCurrentPage);
 
        /* Do some trivial performance monitoring...
@@ -1562,7 +1561,7 @@ static void radeon_cp_dispatch_indirect(struct drm_device * dev,
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
        RING_LOCALS;
-       DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
+       DRM_DEBUG("buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
 
        if (start != end) {
                int offset = (dev_priv->gart_buffers_offset
@@ -1758,7 +1757,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,
                        buf = radeon_freelist_get(dev);
                }
                if (!buf) {
-                       DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
+                       DRM_DEBUG("EAGAIN\n");
                        if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
                                return -EFAULT;
                        return -EAGAIN;
@@ -2413,7 +2412,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
+       DRM_DEBUG("idx=%d s=%d e=%d d=%d\n",
                  indirect->idx, indirect->start, indirect->end,
                  indirect->discard);
 
@@ -2779,7 +2778,7 @@ static int radeon_emit_wait(struct drm_device * dev, int flags)
        drm_radeon_private_t *dev_priv = dev->dev_private;
        RING_LOCALS;
 
-       DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
+       DRM_DEBUG("%x\n", flags);
        switch (flags) {
        case RADEON_WAIT_2D:
                BEGIN_RING(2);
@@ -3035,6 +3034,9 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
        case RADEON_PARAM_VBLANK_CRTC:
                value = radeon_vblank_crtc_get(dev);
                break;
+       case RADEON_PARAM_FB_LOCATION:
+               value = radeon_read_fb_location(dev_priv);
+               break;
        default:
                DRM_DEBUG("Invalid parameter %d\n", param->param);
                return -EINVAL;
index bf8e0e10fe21140daf89b42232846c71df4b8405..5f6238fdf1fa5f13fd2411e5fde9bd3d8b34e270 100644 (file)
@@ -512,7 +512,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
                        DMA_DRAW_PRIMITIVE(count, prim, skip);
 
                        if (vb_stride == vtx_size) {
-                               DMA_COPY(&vtxbuf[vb_stride * start], 
+                               DMA_COPY(&vtxbuf[vb_stride * start],
                                         vtx_size * count);
                        } else {
                                for (i = start; i < start + count; ++i) {
@@ -742,7 +742,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
        while (n != 0) {
                /* Can emit up to 255 vertices (85 triangles) at once. */
                unsigned int count = n > 255 ? 255 : n;
-               
+
                /* Check indices */
                for (i = 0; i < count; ++i) {
                        if (idx[i] > vb_size / (vb_stride * 4)) {
@@ -933,7 +933,7 @@ static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
                                /* j was check in savage_bci_cmdbuf */
                                ret = savage_dispatch_vb_idx(dev_priv,
                                        &cmd_header, (const uint16_t *)cmdbuf,
-                                       (const uint32_t *)vtxbuf, vb_size, 
+                                       (const uint32_t *)vtxbuf, vb_size,
                                        vb_stride);
                                cmdbuf += j;
                                break;
index a6b7ccdaf73deae309099868a1a21a7e13f94a7a..b3878770fce13b64da9fa10dc190343a37c97800 100644 (file)
@@ -115,7 +115,7 @@ static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file
        dev_priv->vram_offset = fb->offset;
 
        mutex_unlock(&dev->struct_mutex);
-       DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
+       DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size);
 
        return 0;
 }
@@ -205,7 +205,7 @@ static int sis_ioctl_agp_init(struct drm_device *dev, void *data,
        dev_priv->agp_offset = agp->offset;
        mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
+       DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size);
        return 0;
 }
 
@@ -249,7 +249,7 @@ int sis_idle(struct drm_device *dev)
                        return 0;
                }
        }
-       
+
        /*
         * Implement a device switch here if needed
         */
index 7009dbddac436fc86fbd1fe20757382d6228541f..94baec692b57713fe6f246d3a296edefafe40c7b 100644 (file)
@@ -179,14 +179,12 @@ static int via_initialize(struct drm_device * dev,
        }
 
        if (dev_priv->ring.virtual_start != NULL) {
-               DRM_ERROR("%s called again without calling cleanup\n",
-                         __FUNCTION__);
+               DRM_ERROR("called again without calling cleanup\n");
                return -EFAULT;
        }
 
        if (!dev->agp || !dev->agp->base) {
-               DRM_ERROR("%s called with no agp memory available\n",
-                         __FUNCTION__);
+               DRM_ERROR("called with no agp memory available\n");
                return -EFAULT;
        }
 
@@ -267,8 +265,7 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
        dev_priv = (drm_via_private_t *) dev->dev_private;
 
        if (dev_priv->ring.virtual_start == NULL) {
-               DRM_ERROR("%s called without initializing AGP ring buffer.\n",
-                         __FUNCTION__);
+               DRM_ERROR("called without initializing AGP ring buffer.\n");
                return -EFAULT;
        }
 
@@ -337,8 +334,7 @@ static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *fi
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf->buf,
-                 cmdbuf->size);
+       DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
 
        ret = via_dispatch_cmdbuffer(dev, cmdbuf);
        if (ret) {
@@ -379,8 +375,7 @@ static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf->buf,
-                 cmdbuf->size);
+       DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
 
        ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf);
        if (ret) {
@@ -648,14 +643,13 @@ static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *
        uint32_t tmp_size, count;
        drm_via_private_t *dev_priv;
 
-       DRM_DEBUG("via cmdbuf_size\n");
+       DRM_DEBUG("\n");
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        dev_priv = (drm_via_private_t *) dev->dev_private;
 
        if (dev_priv->ring.virtual_start == NULL) {
-               DRM_ERROR("%s called without initializing AGP ring buffer.\n",
-                         __FUNCTION__);
+               DRM_ERROR("called without initializing AGP ring buffer.\n");
                return -EFAULT;
        }
 
index c6fd16f3cb434594fb52fc1f1fc2f28309445132..33c5197b73c4a79b9c6b95849debe94b68dda549 100644 (file)
@@ -1,5 +1,5 @@
 /* via_dmablit.c -- PCI DMA BitBlt support for the VIA Unichrome/Pro
- * 
+ *
  * Copyright (C) 2005 Thomas Hellstrom, All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: 
+ * Authors:
  *    Thomas Hellstrom.
  *    Partially based on code obtained from Digeo Inc.
  */
 
 
 /*
- * Unmaps the DMA mappings. 
- * FIXME: Is this a NoOp on x86? Also 
- * FIXME: What happens if this one is called and a pending blit has previously done 
- * the same DMA mappings? 
+ * Unmaps the DMA mappings.
+ * FIXME: Is this a NoOp on x86? Also
+ * FIXME: What happens if this one is called and a pending blit has previously done
+ * the same DMA mappings?
  */
 
 #include "drmP.h"
@@ -65,7 +65,7 @@ via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
        int num_desc = vsg->num_desc;
        unsigned cur_descriptor_page = num_desc / vsg->descriptors_per_page;
        unsigned descriptor_this_page = num_desc % vsg->descriptors_per_page;
-       drm_via_descriptor_t *desc_ptr = vsg->desc_pages[cur_descriptor_page] + 
+       drm_via_descriptor_t *desc_ptr = vsg->desc_pages[cur_descriptor_page] +
                descriptor_this_page;
        dma_addr_t next = vsg->chain_start;
 
@@ -73,7 +73,7 @@ via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
                if (descriptor_this_page-- == 0) {
                        cur_descriptor_page--;
                        descriptor_this_page = vsg->descriptors_per_page - 1;
-                       desc_ptr = vsg->desc_pages[cur_descriptor_page] + 
+                       desc_ptr = vsg->desc_pages[cur_descriptor_page] +
                                descriptor_this_page;
                }
                dma_unmap_single(&pdev->dev, next, sizeof(*desc_ptr), DMA_TO_DEVICE);
@@ -93,7 +93,7 @@ via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
 static void
 via_map_blit_for_device(struct pci_dev *pdev,
                   const drm_via_dmablit_t *xfer,
-                  drm_via_sg_info_t *vsg, 
+                  drm_via_sg_info_t *vsg,
                   int mode)
 {
        unsigned cur_descriptor_page = 0;
@@ -110,7 +110,7 @@ via_map_blit_for_device(struct pci_dev *pdev,
        dma_addr_t next = 0 | VIA_DMA_DPR_EC;
        drm_via_descriptor_t *desc_ptr = NULL;
 
-       if (mode == 1) 
+       if (mode == 1)
                desc_ptr = vsg->desc_pages[cur_descriptor_page];
 
        for (cur_line = 0; cur_line < xfer->num_lines; ++cur_line) {
@@ -118,24 +118,24 @@ via_map_blit_for_device(struct pci_dev *pdev,
                line_len = xfer->line_length;
                cur_fb = fb_addr;
                cur_mem = mem_addr;
-               
+
                while (line_len > 0) {
 
                        remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
                        line_len -= remaining_len;
 
                        if (mode == 1) {
-                               desc_ptr->mem_addr = 
-                                       dma_map_page(&pdev->dev, 
-                                                    vsg->pages[VIA_PFN(cur_mem) - 
+                               desc_ptr->mem_addr =
+                                       dma_map_page(&pdev->dev,
+                                                    vsg->pages[VIA_PFN(cur_mem) -
                                                                VIA_PFN(first_addr)],
-                                                    VIA_PGOFF(cur_mem), remaining_len, 
+                                                    VIA_PGOFF(cur_mem), remaining_len,
                                                     vsg->direction);
                                desc_ptr->dev_addr = cur_fb;
-                               
+
                                desc_ptr->size = remaining_len;
                                desc_ptr->next = (uint32_t) next;
-                               next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr), 
+                               next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr),
                                                      DMA_TO_DEVICE);
                                desc_ptr++;
                                if (++num_descriptors_this_page >= vsg->descriptors_per_page) {
@@ -143,12 +143,12 @@ via_map_blit_for_device(struct pci_dev *pdev,
                                        desc_ptr = vsg->desc_pages[++cur_descriptor_page];
                                }
                        }
-                       
+
                        num_desc++;
                        cur_mem += remaining_len;
                        cur_fb += remaining_len;
                }
-               
+
                mem_addr += xfer->mem_stride;
                fb_addr += xfer->fb_stride;
        }
@@ -161,14 +161,14 @@ via_map_blit_for_device(struct pci_dev *pdev,
 }
 
 /*
- * Function that frees up all resources for a blit. It is usable even if the 
+ * Function that frees up all resources for a blit. It is usable even if the
  * blit info has only been partially built as long as the status enum is consistent
  * with the actual status of the used resources.
  */
 
 
 static void
-via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg) 
+via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
 {
        struct page *page;
        int i;
@@ -185,7 +185,7 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
        case dr_via_pages_locked:
                for (i=0; i<vsg->num_pages; ++i) {
                        if ( NULL != (page = vsg->pages[i])) {
-                               if (! PageReserved(page) && (DMA_FROM_DEVICE == vsg->direction)) 
+                               if (! PageReserved(page) && (DMA_FROM_DEVICE == vsg->direction))
                                        SetPageDirty(page);
                                page_cache_release(page);
                        }
@@ -200,7 +200,7 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
                vsg->bounce_buffer = NULL;
        }
        vsg->free_on_sequence = 0;
-}              
+}
 
 /*
  * Fire a blit engine.
@@ -213,7 +213,7 @@ via_fire_dmablit(struct drm_device *dev, drm_via_sg_info_t *vsg, int engine)
 
        VIA_WRITE(VIA_PCI_DMA_MAR0 + engine*0x10, 0);
        VIA_WRITE(VIA_PCI_DMA_DAR0 + engine*0x10, 0);
-       VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DD | VIA_DMA_CSR_TD | 
+       VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DD | VIA_DMA_CSR_TD |
                  VIA_DMA_CSR_DE);
        VIA_WRITE(VIA_PCI_DMA_MR0  + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
        VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0);
@@ -233,9 +233,9 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg,  drm_via_dmablit_t *xfer)
 {
        int ret;
        unsigned long first_pfn = VIA_PFN(xfer->mem_addr);
-       vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride -1)) - 
+       vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride -1)) -
                first_pfn + 1;
-       
+
        if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages)))
                return -ENOMEM;
        memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
@@ -248,7 +248,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg,  drm_via_dmablit_t *xfer)
 
        up_read(&current->mm->mmap_sem);
        if (ret != vsg->num_pages) {
-               if (ret < 0) 
+               if (ret < 0)
                        return ret;
                vsg->state = dr_via_pages_locked;
                return -EINVAL;
@@ -264,21 +264,21 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg,  drm_via_dmablit_t *xfer)
  * quite large for some blits, and pages don't need to be contingous.
  */
 
-static int 
+static int
 via_alloc_desc_pages(drm_via_sg_info_t *vsg)
 {
        int i;
-       
+
        vsg->descriptors_per_page = PAGE_SIZE / sizeof( drm_via_descriptor_t);
-       vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / 
+       vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) /
                vsg->descriptors_per_page;
 
        if (NULL ==  (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL)))
                return -ENOMEM;
-       
+
        vsg->state = dr_via_desc_pages_alloc;
        for (i=0; i<vsg->num_desc_pages; ++i) {
-               if (NULL == (vsg->desc_pages[i] = 
+               if (NULL == (vsg->desc_pages[i] =
                             (drm_via_descriptor_t *) __get_free_page(GFP_KERNEL)))
                        return -ENOMEM;
        }
@@ -286,7 +286,7 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
                  vsg->num_desc);
        return 0;
 }
-                       
+
 static void
 via_abort_dmablit(struct drm_device *dev, int engine)
 {
@@ -300,7 +300,7 @@ via_dmablit_engine_off(struct drm_device *dev, int engine)
 {
        drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
 
-       VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD | VIA_DMA_CSR_DD); 
+       VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD | VIA_DMA_CSR_DD);
 }
 
 
@@ -311,7 +311,7 @@ via_dmablit_engine_off(struct drm_device *dev, int engine)
  * task. Basically the task of the interrupt handler is to submit a new blit to the engine, while
  * the workqueue task takes care of processing associated with the old blit.
  */
-               
+
 void
 via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
 {
@@ -331,19 +331,19 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
                spin_lock_irqsave(&blitq->blit_lock, irqsave);
        }
 
-       done_transfer = blitq->is_active && 
+       done_transfer = blitq->is_active &&
          (( status = VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD);
-       done_transfer = done_transfer || ( blitq->aborting && !(status & VIA_DMA_CSR_DE)); 
+       done_transfer = done_transfer || ( blitq->aborting && !(status & VIA_DMA_CSR_DE));
 
        cur = blitq->cur;
        if (done_transfer) {
 
                blitq->blits[cur]->aborted = blitq->aborting;
                blitq->done_blit_handle++;
-               DRM_WAKEUP(blitq->blit_queue + cur);            
+               DRM_WAKEUP(blitq->blit_queue + cur);
 
                cur++;
-               if (cur >= VIA_NUM_BLIT_SLOTS) 
+               if (cur >= VIA_NUM_BLIT_SLOTS)
                        cur = 0;
                blitq->cur = cur;
 
@@ -355,7 +355,7 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
 
                blitq->is_active = 0;
                blitq->aborting = 0;
-               schedule_work(&blitq->wq);      
+               schedule_work(&blitq->wq);
 
        } else if (blitq->is_active && time_after_eq(jiffies, blitq->end)) {
 
@@ -367,7 +367,7 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
                blitq->aborting = 1;
                blitq->end = jiffies + DRM_HZ;
        }
-                       
+
        if (!blitq->is_active) {
                if (blitq->num_outstanding) {
                        via_fire_dmablit(dev, blitq->blits[cur], engine);
@@ -383,14 +383,14 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
                        }
                        via_dmablit_engine_off(dev, engine);
                }
-       }               
+       }
 
        if (from_irq) {
                spin_unlock(&blitq->blit_lock);
        } else {
                spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
        }
-} 
+}
 
 
 
@@ -426,13 +426,13 @@ via_dmablit_active(drm_via_blitq_t *blitq, int engine, uint32_t handle, wait_que
 
        return active;
 }
-       
+
 /*
  * Sync. Wait for at least three seconds for the blit to be performed.
  */
 
 static int
-via_dmablit_sync(struct drm_device *dev, uint32_t handle, int engine) 
+via_dmablit_sync(struct drm_device *dev, uint32_t handle, int engine)
 {
 
        drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
@@ -441,12 +441,12 @@ via_dmablit_sync(struct drm_device *dev, uint32_t handle, int engine)
        int ret = 0;
 
        if (via_dmablit_active(blitq, engine, handle, &queue)) {
-               DRM_WAIT_ON(ret, *queue, 3 * DRM_HZ, 
+               DRM_WAIT_ON(ret, *queue, 3 * DRM_HZ,
                            !via_dmablit_active(blitq, engine, handle, NULL));
        }
        DRM_DEBUG("DMA blit sync handle 0x%x engine %d returned %d\n",
                  handle, engine, ret);
-       
+
        return ret;
 }
 
@@ -468,12 +468,12 @@ via_dmablit_timer(unsigned long data)
        struct drm_device *dev = blitq->dev;
        int engine = (int)
                (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues);
-               
-       DRM_DEBUG("Polling timer called for engine %d, jiffies %lu\n", engine, 
+
+       DRM_DEBUG("Polling timer called for engine %d, jiffies %lu\n", engine,
                  (unsigned long) jiffies);
 
        via_dmablit_handler(dev, engine, 0);
-       
+
        if (!timer_pending(&blitq->poll_timer)) {
                mod_timer(&blitq->poll_timer, jiffies + 1);
 
@@ -497,7 +497,7 @@ via_dmablit_timer(unsigned long data)
  */
 
 
-static void 
+static void
 via_dmablit_workqueue(struct work_struct *work)
 {
        drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq);
@@ -505,38 +505,38 @@ via_dmablit_workqueue(struct work_struct *work)
        unsigned long irqsave;
        drm_via_sg_info_t *cur_sg;
        int cur_released;
-       
-       
-       DRM_DEBUG("Workqueue task called for blit engine %ld\n",(unsigned long) 
+
+
+       DRM_DEBUG("Workqueue task called for blit engine %ld\n",(unsigned long)
                  (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues));
 
        spin_lock_irqsave(&blitq->blit_lock, irqsave);
-       
+
        while(blitq->serviced != blitq->cur) {
 
                cur_released = blitq->serviced++;
 
                DRM_DEBUG("Releasing blit slot %d\n", cur_released);
 
-               if (blitq->serviced >= VIA_NUM_BLIT_SLOTS) 
+               if (blitq->serviced >= VIA_NUM_BLIT_SLOTS)
                        blitq->serviced = 0;
-               
+
                cur_sg = blitq->blits[cur_released];
                blitq->num_free++;
-                               
+
                spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
-               
+
                DRM_WAKEUP(&blitq->busy_queue);
-               
+
                via_free_sg_info(dev->pdev, cur_sg);
                kfree(cur_sg);
-               
+
                spin_lock_irqsave(&blitq->blit_lock, irqsave);
        }
 
        spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
 }
-       
+
 
 /*
  * Init all blit engines. Currently we use two, but some hardware have 4.
@@ -550,8 +550,8 @@ via_init_dmablit(struct drm_device *dev)
        drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
        drm_via_blitq_t *blitq;
 
-       pci_set_master(dev->pdev);      
-       
+       pci_set_master(dev->pdev);
+
        for (i=0; i< VIA_NUM_BLIT_ENGINES; ++i) {
                blitq = dev_priv->blit_queues + i;
                blitq->dev = dev;
@@ -572,20 +572,20 @@ via_init_dmablit(struct drm_device *dev)
                INIT_WORK(&blitq->wq, via_dmablit_workqueue);
                setup_timer(&blitq->poll_timer, via_dmablit_timer,
                                (unsigned long)blitq);
-       }       
+       }
 }
 
 /*
  * Build all info and do all mappings required for a blit.
  */
-               
+
 
 static int
 via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
 {
        int draw = xfer->to_fb;
        int ret = 0;
-       
+
        vsg->direction = (draw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
        vsg->bounce_buffer = NULL;
 
@@ -599,7 +599,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
        /*
         * Below check is a driver limitation, not a hardware one. We
         * don't want to lock unused pages, and don't want to incoporate the
-        * extra logic of avoiding them. Make sure there are no. 
+        * extra logic of avoiding them. Make sure there are no.
         * (Not a big limitation anyway.)
         */
 
@@ -625,11 +625,11 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
        if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
                DRM_ERROR("Too large PCI DMA bitblt.\n");
                return -EINVAL;
-       }               
+       }
 
-       /* 
+       /*
         * we allow a negative fb stride to allow flipping of images in
-        * transfer. 
+        * transfer.
         */
 
        if (xfer->mem_stride < xfer->line_length ||
@@ -653,11 +653,11 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
 #else
        if ((((unsigned long)xfer->mem_addr & 15) ||
              ((unsigned long)xfer->fb_addr & 3)) ||
-          ((xfer->num_lines > 1) && 
+          ((xfer->num_lines > 1) &&
           ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
                DRM_ERROR("Invalid DRM bitblt alignment.\n");
                return -EINVAL;
-       }       
+       }
 #endif
 
        if (0 != (ret = via_lock_all_dma_pages(vsg, xfer))) {
@@ -673,17 +673,17 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
                return ret;
        }
        via_map_blit_for_device(dev->pdev, xfer, vsg, 1);
-       
+
        return 0;
 }
-       
+
 
 /*
  * Reserve one free slot in the blit queue. Will wait for one second for one
  * to become available. Otherwise -EBUSY is returned.
  */
 
-static int 
+static int
 via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
 {
        int ret=0;
@@ -698,10 +698,10 @@ via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
                if (ret) {
                        return (-EINTR == ret) ? -EAGAIN : ret;
                }
-               
+
                spin_lock_irqsave(&blitq->blit_lock, irqsave);
        }
-       
+
        blitq->num_free--;
        spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
 
@@ -712,7 +712,7 @@ via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
  * Hand back a free slot if we changed our mind.
  */
 
-static void 
+static void
 via_dmablit_release_slot(drm_via_blitq_t *blitq)
 {
        unsigned long irqsave;
@@ -728,8 +728,8 @@ via_dmablit_release_slot(drm_via_blitq_t *blitq)
  */
 
 
-static int 
-via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)    
+static int
+via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
 {
        drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
        drm_via_sg_info_t *vsg;
@@ -760,15 +760,15 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
        spin_lock_irqsave(&blitq->blit_lock, irqsave);
 
        blitq->blits[blitq->head++] = vsg;
-       if (blitq->head >= VIA_NUM_BLIT_SLOTS) 
+       if (blitq->head >= VIA_NUM_BLIT_SLOTS)
                blitq->head = 0;
        blitq->num_outstanding++;
-       xfer->sync.sync_handle = ++blitq->cur_blit_handle; 
+       xfer->sync.sync_handle = ++blitq->cur_blit_handle;
 
        spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
        xfer->sync.engine = engine;
 
-               via_dmablit_handler(dev, engine, 0);
+       via_dmablit_handler(dev, engine, 0);
 
        return 0;
 }
@@ -776,7 +776,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
 /*
  * Sync on a previously submitted blit. Note that the X server use signals extensively, and
  * that there is a very big probability that this IOCTL will be interrupted by a signal. In that
- * case it returns with -EAGAIN for the signal to be delivered. 
+ * case it returns with -EAGAIN for the signal to be delivered.
  * The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock().
  */
 
@@ -786,7 +786,7 @@ via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_pri
        drm_via_blitsync_t *sync = data;
        int err;
 
-       if (sync->engine >= VIA_NUM_BLIT_ENGINES) 
+       if (sync->engine >= VIA_NUM_BLIT_ENGINES)
                return -EINVAL;
 
        err = via_dmablit_sync(dev, sync->sync_handle, sync->engine);
@@ -796,15 +796,15 @@ via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_pri
 
        return err;
 }
-       
+
 
 /*
  * Queue a blit and hand back a handle to be used for sync. This IOCTL may be interrupted by a signal
- * while waiting for a free slot in the blit queue. In that case it returns with -EAGAIN and should 
+ * while waiting for a free slot in the blit queue. In that case it returns with -EAGAIN and should
  * be reissued. See the above IOCTL code.
  */
 
-int 
+int
 via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv )
 {
        drm_via_dmablit_t *xfer = data;
index 6f6a513d51474a6ba72a5f7aca524207e1fc2785..7408a547a036937af9bccc52ee77ab2e5a0e3fb2 100644 (file)
@@ -1,5 +1,5 @@
 /* via_dmablit.h -- PCI DMA BitBlt support for the VIA Unichrome/Pro
- * 
+ *
  * Copyright 2005 Thomas Hellstrom.
  * All Rights Reserved.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: 
+ * Authors:
  *    Thomas Hellstrom.
  *    Register info from Digeo Inc.
  */
@@ -67,7 +67,7 @@ typedef struct _drm_via_blitq {
        unsigned cur;
        unsigned num_free;
        unsigned num_outstanding;
-       unsigned long end;  
+       unsigned long end;
         int aborting;
        int is_active;
        drm_via_sg_info_t *blits[VIA_NUM_BLIT_SLOTS];
@@ -77,46 +77,46 @@ typedef struct _drm_via_blitq {
        struct work_struct wq;
        struct timer_list poll_timer;
 } drm_via_blitq_t;
-       
 
-/* 
+
+/*
  *  PCI DMA Registers
  *  Channels 2 & 3 don't seem to be implemented in hardware.
  */
-#define VIA_PCI_DMA_MAR0            0xE40   /* Memory Address Register of Channel 0 */ 
-#define VIA_PCI_DMA_DAR0            0xE44   /* Device Address Register of Channel 0 */ 
-#define VIA_PCI_DMA_BCR0            0xE48   /* Byte Count Register of Channel 0 */ 
-#define VIA_PCI_DMA_DPR0            0xE4C   /* Descriptor Pointer Register of Channel 0 */ 
-
-#define VIA_PCI_DMA_MAR1            0xE50   /* Memory Address Register of Channel 1 */ 
-#define VIA_PCI_DMA_DAR1            0xE54   /* Device Address Register of Channel 1 */ 
-#define VIA_PCI_DMA_BCR1            0xE58   /* Byte Count Register of Channel 1 */ 
-#define VIA_PCI_DMA_DPR1            0xE5C   /* Descriptor Pointer Register of Channel 1 */ 
-
-#define VIA_PCI_DMA_MAR2            0xE60   /* Memory Address Register of Channel 2 */ 
-#define VIA_PCI_DMA_DAR2            0xE64   /* Device Address Register of Channel 2 */ 
-#define VIA_PCI_DMA_BCR2            0xE68   /* Byte Count Register of Channel 2 */ 
-#define VIA_PCI_DMA_DPR2            0xE6C   /* Descriptor Pointer Register of Channel 2 */ 
-
-#define VIA_PCI_DMA_MAR3            0xE70   /* Memory Address Register of Channel 3 */ 
-#define VIA_PCI_DMA_DAR3            0xE74   /* Device Address Register of Channel 3 */ 
-#define VIA_PCI_DMA_BCR3            0xE78   /* Byte Count Register of Channel 3 */ 
-#define VIA_PCI_DMA_DPR3            0xE7C   /* Descriptor Pointer Register of Channel 3 */ 
-
-#define VIA_PCI_DMA_MR0             0xE80   /* Mode Register of Channel 0 */ 
-#define VIA_PCI_DMA_MR1             0xE84   /* Mode Register of Channel 1 */ 
-#define VIA_PCI_DMA_MR2             0xE88   /* Mode Register of Channel 2 */ 
-#define VIA_PCI_DMA_MR3             0xE8C   /* Mode Register of Channel 3 */ 
-
-#define VIA_PCI_DMA_CSR0            0xE90   /* Command/Status Register of Channel 0 */ 
-#define VIA_PCI_DMA_CSR1            0xE94   /* Command/Status Register of Channel 1 */ 
-#define VIA_PCI_DMA_CSR2            0xE98   /* Command/Status Register of Channel 2 */ 
-#define VIA_PCI_DMA_CSR3            0xE9C   /* Command/Status Register of Channel 3 */ 
-
-#define VIA_PCI_DMA_PTR             0xEA0   /* Priority Type Register */ 
-
-/* Define for DMA engine */ 
+
+#define VIA_PCI_DMA_MAR0            0xE40   /* Memory Address Register of Channel 0 */
+#define VIA_PCI_DMA_DAR0            0xE44   /* Device Address Register of Channel 0 */
+#define VIA_PCI_DMA_BCR0            0xE48   /* Byte Count Register of Channel 0 */
+#define VIA_PCI_DMA_DPR0            0xE4C   /* Descriptor Pointer Register of Channel 0 */
+
+#define VIA_PCI_DMA_MAR1            0xE50   /* Memory Address Register of Channel 1 */
+#define VIA_PCI_DMA_DAR1            0xE54   /* Device Address Register of Channel 1 */
+#define VIA_PCI_DMA_BCR1            0xE58   /* Byte Count Register of Channel 1 */
+#define VIA_PCI_DMA_DPR1            0xE5C   /* Descriptor Pointer Register of Channel 1 */
+
+#define VIA_PCI_DMA_MAR2            0xE60   /* Memory Address Register of Channel 2 */
+#define VIA_PCI_DMA_DAR2            0xE64   /* Device Address Register of Channel 2 */
+#define VIA_PCI_DMA_BCR2            0xE68   /* Byte Count Register of Channel 2 */
+#define VIA_PCI_DMA_DPR2            0xE6C   /* Descriptor Pointer Register of Channel 2 */
+
+#define VIA_PCI_DMA_MAR3            0xE70   /* Memory Address Register of Channel 3 */
+#define VIA_PCI_DMA_DAR3            0xE74   /* Device Address Register of Channel 3 */
+#define VIA_PCI_DMA_BCR3            0xE78   /* Byte Count Register of Channel 3 */
+#define VIA_PCI_DMA_DPR3            0xE7C   /* Descriptor Pointer Register of Channel 3 */
+
+#define VIA_PCI_DMA_MR0             0xE80   /* Mode Register of Channel 0 */
+#define VIA_PCI_DMA_MR1             0xE84   /* Mode Register of Channel 1 */
+#define VIA_PCI_DMA_MR2             0xE88   /* Mode Register of Channel 2 */
+#define VIA_PCI_DMA_MR3             0xE8C   /* Mode Register of Channel 3 */
+
+#define VIA_PCI_DMA_CSR0            0xE90   /* Command/Status Register of Channel 0 */
+#define VIA_PCI_DMA_CSR1            0xE94   /* Command/Status Register of Channel 1 */
+#define VIA_PCI_DMA_CSR2            0xE98   /* Command/Status Register of Channel 2 */
+#define VIA_PCI_DMA_CSR3            0xE9C   /* Command/Status Register of Channel 3 */
+
+#define VIA_PCI_DMA_PTR             0xEA0   /* Priority Type Register */
+
+/* Define for DMA engine */
 /* DPR */
 #define VIA_DMA_DPR_EC         (1<<1)  /* end of chain */
 #define VIA_DMA_DPR_DDIE       (1<<2)  /* descriptor done interrupt enable */
index 8f53c76062e9bb66d8034e81b61be0e824712b32..a3b5c102b06716108486d6c70d771bf63dc58d5a 100644 (file)
@@ -35,7 +35,7 @@
 #include "via_drmclient.h"
 #endif
 
-#define VIA_NR_SAREA_CLIPRECTS                 8
+#define VIA_NR_SAREA_CLIPRECTS         8
 #define VIA_NR_XVMC_PORTS               10
 #define VIA_NR_XVMC_LOCKS               5
 #define VIA_MAX_CACHELINE_SIZE          64
@@ -259,7 +259,7 @@ typedef struct drm_via_blitsync {
 typedef struct drm_via_dmablit {
        uint32_t num_lines;
        uint32_t line_length;
-       
+
        uint32_t fb_addr;
        uint32_t fb_stride;
 
index 2d4957ab256a39410b9cfec8d06a9e4bab5c7e40..80c01cdfa37d54db94ec5a382f83ec4e6b026432 100644 (file)
@@ -71,7 +71,7 @@ static struct drm_driver driver = {
                 .name = DRIVER_NAME,
                 .id_table = pciidlist,
        },
-       
+
        .name = DRIVER_NAME,
        .desc = DRIVER_DESC,
        .date = DRIVER_DATE,
index 9c1d52bc92d764dc3c58169dcc5b391c5bfba290..c6bb978a110673821a3aa6db6e3cefd32bcc20ce 100644 (file)
@@ -169,9 +169,9 @@ int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
        unsigned int cur_vblank;
        int ret = 0;
 
-       DRM_DEBUG("viadrv_vblank_wait\n");
+       DRM_DEBUG("\n");
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
@@ -201,24 +201,23 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
        maskarray_t *masks;
        int real_irq;
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
        if (irq >= drm_via_irq_num) {
-               DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
-                         irq);
+               DRM_ERROR("Trying to wait on unknown irq %d\n", irq);
                return -EINVAL;
        }
 
        real_irq = dev_priv->irq_map[irq];
 
        if (real_irq < 0) {
-               DRM_ERROR("%s Video IRQ %d not available on this hardware.\n",
-                         __FUNCTION__, irq);
+               DRM_ERROR("Video IRQ %d not available on this hardware.\n",
+                         irq);
                return -EINVAL;
        }
 
@@ -251,7 +250,7 @@ void via_driver_irq_preinstall(struct drm_device * dev)
        drm_via_irq_t *cur_irq;
        int i;
 
-       DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);
+       DRM_DEBUG("dev_priv: %p\n", dev_priv);
        if (dev_priv) {
                cur_irq = dev_priv->via_irqs;
 
@@ -298,7 +297,7 @@ void via_driver_irq_postinstall(struct drm_device * dev)
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
        u32 status;
 
-       DRM_DEBUG("via_driver_irq_postinstall\n");
+       DRM_DEBUG("\n");
        if (dev_priv) {
                status = VIA_READ(VIA_REG_INTERRUPT);
                VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
@@ -317,7 +316,7 @@ void via_driver_irq_uninstall(struct drm_device * dev)
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
        u32 status;
 
-       DRM_DEBUG("driver_irq_uninstall)\n");
+       DRM_DEBUG("\n");
        if (dev_priv) {
 
                /* Some more magic, oh for some data sheets ! */
@@ -344,7 +343,7 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
                return -EINVAL;
 
        if (irqwait->request.irq >= dev_priv->num_irqs) {
-               DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
+               DRM_ERROR("Trying to wait on unknown irq %d\n",
                          irqwait->request.irq);
                return -EINVAL;
        }
@@ -362,8 +361,7 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
        }
 
        if (irqwait->request.type & VIA_IRQ_SIGNAL) {
-               DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n",
-                         __FUNCTION__);
+               DRM_ERROR("Signals on Via IRQs not implemented yet.\n");
                return -EINVAL;
        }
 
index 10091507a0dc12c35a289da36750230112d197a8..a967556be014612f731125e8b9f77437a334921b 100644 (file)
@@ -29,7 +29,7 @@ static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init)
 {
        drm_via_private_t *dev_priv = dev->dev_private;
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        dev_priv->sarea = drm_getsarea(dev);
        if (!dev_priv->sarea) {
@@ -79,7 +79,7 @@ int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        drm_via_init_t *init = data;
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        switch (init->func) {
        case VIA_INIT_MAP:
@@ -121,4 +121,3 @@ int via_driver_unload(struct drm_device *dev)
 
        return 0;
 }
-
index 3ffbf86498331453f64bdf1d7b7060d655088099..e64094916e4fcf3f26b6482702c218a55583ec7f 100644 (file)
@@ -53,7 +53,7 @@ int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
        dev_priv->agp_offset = agp->offset;
        mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
+       DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size);
        return 0;
 }
 
@@ -77,7 +77,7 @@ int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
        dev_priv->vram_offset = fb->offset;
 
        mutex_unlock(&dev->struct_mutex);
-       DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
+       DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size);
 
        return 0;
 
@@ -113,7 +113,7 @@ void via_lastclose(struct drm_device *dev)
        dev_priv->vram_initialized = 0;
        dev_priv->agp_initialized = 0;
        mutex_unlock(&dev->struct_mutex);
-}      
+}
 
 int via_mem_alloc(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
index c15e75b54cb17783bcf2a627e85e1c82e6c5374b..6ec04ac1245991ffea7bf1a5cf1197f4b411ea46 100644 (file)
@@ -33,7 +33,7 @@ void via_init_futex(drm_via_private_t * dev_priv)
 {
        unsigned int i;
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
                DRM_INIT_WAITQUEUE(&(dev_priv->decoder_queue[i]));
@@ -73,7 +73,7 @@ int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_
        drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
        int ret = 0;
 
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("\n");
 
        if (fx->lock > VIA_NR_XVMC_LOCKS)
                return -EFAULT;
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 179223a1741437ad6d8749b99909bdc1f5289588..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;
 
@@ -446,6 +473,13 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {
                        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 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 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 47420787a0174933c82777c3e14e689bb784ef0f..68c2e923469195295ed74c028eb360e2588e9a19 100644 (file)
@@ -1,41 +1,24 @@
 /*
  *          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/errno.h>
 #include <linux/signal.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;
@@ -189,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 */
 
@@ -241,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 {
@@ -277,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 {
@@ -355,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;
@@ -437,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;
 
@@ -529,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;
@@ -1013,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;
@@ -1044,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) {
@@ -1073,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;
@@ -1096,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;
@@ -1114,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)
@@ -1145,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);
                }
        }
@@ -1160,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)
@@ -1174,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);
                }
        }
@@ -1189,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 ||
@@ -1197,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;
@@ -1222,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;
 
@@ -1236,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;
 
@@ -1599,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);
        }
 }
 
@@ -1703,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);
        }
 }
 
@@ -1759,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;
 
@@ -1829,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);
@@ -2983,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);
@@ -3010,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 bf1bee4..0000000
+++ /dev/null
@@ -1,2816 +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/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 d130b87d8ed793186e63e13dbb7fc139378076b7..8fc4fe4e38f1bdb728f751955aa69d3f9fb06dd8 100644 (file)
@@ -78,8 +78,6 @@
         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);
@@ -314,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)
 {
@@ -486,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)
@@ -505,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
@@ -514,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;
@@ -526,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;
@@ -1091,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) {
@@ -1526,25 +1517,6 @@ static void rc_start(struct tty_struct * tty)
        spin_unlock_irqrestore(&riscom_lock, 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 */
-}
-
 static void rc_hangup(struct tty_struct * tty)
 {
        struct riscom_port *port = (struct riscom_port *)tty->driver_data;
@@ -1556,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;
@@ -1586,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,
@@ -1618,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;
@@ -1650,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);
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 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
diff --git a/drivers/char/xilinx_hwicap/Makefile b/drivers/char/xilinx_hwicap/Makefile
new file mode 100644 (file)
index 0000000..5491cbc
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the Xilinx OPB hwicap driver
+#
+
+obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap_m.o 
+xilinx_hwicap_m-y := xilinx_hwicap.o fifo_icap.o buffer_icap.o
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c
new file mode 100644 (file)
index 0000000..dfea2bd
--- /dev/null
@@ -0,0 +1,380 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2003-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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 "buffer_icap.h"
+
+/* Indicates how many bytes will fit in a buffer. (1 BRAM) */
+#define XHI_MAX_BUFFER_BYTES        2048
+#define XHI_MAX_BUFFER_INTS         (XHI_MAX_BUFFER_BYTES >> 2)
+
+/* File access and error constants */
+#define XHI_DEVICE_READ_ERROR       -1
+#define XHI_DEVICE_WRITE_ERROR      -2
+#define XHI_BUFFER_OVERFLOW_ERROR   -3
+
+#define XHI_DEVICE_READ             0x1
+#define XHI_DEVICE_WRITE            0x0
+
+/* Constants for checking transfer status */
+#define XHI_CYCLE_DONE              0
+#define XHI_CYCLE_EXECUTING         1
+
+/* buffer_icap register offsets */
+
+/* Size of transfer, read & write */
+#define XHI_SIZE_REG_OFFSET        0x800L
+/* offset into bram, read & write */
+#define XHI_BRAM_OFFSET_REG_OFFSET 0x804L
+/* Read not Configure, direction of transfer.  Write only */
+#define XHI_RNC_REG_OFFSET         0x808L
+/* Indicates transfer complete. Read only */
+#define XHI_STATUS_REG_OFFSET      0x80CL
+
+/* Constants for setting the RNC register */
+#define XHI_CONFIGURE              0x0UL
+#define XHI_READBACK               0x1UL
+
+/* Constants for the Done register */
+#define XHI_NOT_FINISHED           0x0UL
+#define XHI_FINISHED               0x1UL
+
+#define XHI_BUFFER_START 0
+
+/**
+ * buffer_icap_get_status: Get the contents of the status register.
+ * @parameter base_address: is the base address of the device
+ *
+ * The status register contains the ICAP status and the done bit.
+ *
+ * D8 - cfgerr
+ * D7 - dalign
+ * D6 - rip
+ * D5 - in_abort_l
+ * D4 - Always 1
+ * D3 - Always 1
+ * D2 - Always 1
+ * D1 - Always 1
+ * D0 - Done bit
+ **/
+static inline u32 buffer_icap_get_status(void __iomem *base_address)
+{
+       return in_be32(base_address + XHI_STATUS_REG_OFFSET);
+}
+
+/**
+ * buffer_icap_get_bram: Reads data from the storage buffer bram.
+ * @parameter base_address: contains the base address of the component.
+ * @parameter offset: The word offset from which the data should be read.
+ *
+ * A bram is used as a configuration memory cache.  One frame of data can
+ * be stored in this "storage buffer".
+ **/
+static inline u32 buffer_icap_get_bram(void __iomem *base_address,
+               u32 offset)
+{
+       return in_be32(base_address + (offset << 2));
+}
+
+/**
+ * buffer_icap_busy: Return true if the icap device is busy
+ * @parameter base_address: is the base address of the device
+ *
+ * The queries the low order bit of the status register, which
+ * indicates whether the current configuration or readback operation
+ * has completed.
+ **/
+static inline bool buffer_icap_busy(void __iomem *base_address)
+{
+       return (buffer_icap_get_status(base_address) & 1) == XHI_NOT_FINISHED;
+}
+
+/**
+ * buffer_icap_busy: Return true if the icap device is not busy
+ * @parameter base_address: is the base address of the device
+ *
+ * The queries the low order bit of the status register, which
+ * indicates whether the current configuration or readback operation
+ * has completed.
+ **/
+static inline bool buffer_icap_done(void __iomem *base_address)
+{
+       return (buffer_icap_get_status(base_address) & 1) == XHI_FINISHED;
+}
+
+/**
+ * buffer_icap_set_size: Set the size register.
+ * @parameter base_address: is the base address of the device
+ * @parameter data: The size in bytes.
+ *
+ * The size register holds the number of 8 bit bytes to transfer between
+ * bram and the icap (or icap to bram).
+ **/
+static inline void buffer_icap_set_size(void __iomem *base_address,
+               u32 data)
+{
+       out_be32(base_address + XHI_SIZE_REG_OFFSET, data);
+}
+
+/**
+ * buffer_icap_mSetoffsetReg: Set the bram offset register.
+ * @parameter base_address: contains the base address of the device.
+ * @parameter data: is the value to be written to the data register.
+ *
+ * The bram offset register holds the starting bram address to transfer
+ * data from during configuration or write data to during readback.
+ **/
+static inline void buffer_icap_set_offset(void __iomem *base_address,
+               u32 data)
+{
+       out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data);
+}
+
+/**
+ * buffer_icap_set_rnc: Set the RNC (Readback not Configure) register.
+ * @parameter base_address: contains the base address of the device.
+ * @parameter data: is the value to be written to the data register.
+ *
+ * The RNC register determines the direction of the data transfer.  It
+ * controls whether a configuration or readback take place.  Writing to
+ * this register initiates the transfer.  A value of 1 initiates a
+ * readback while writing a value of 0 initiates a configuration.
+ **/
+static inline void buffer_icap_set_rnc(void __iomem *base_address,
+               u32 data)
+{
+       out_be32(base_address + XHI_RNC_REG_OFFSET, data);
+}
+
+/**
+ * buffer_icap_set_bram: Write data to the storage buffer bram.
+ * @parameter base_address: contains the base address of the component.
+ * @parameter offset: The word offset at which the data should be written.
+ * @parameter data: The value to be written to the bram offset.
+ *
+ * A bram is used as a configuration memory cache.  One frame of data can
+ * be stored in this "storage buffer".
+ **/
+static inline void buffer_icap_set_bram(void __iomem *base_address,
+               u32 offset, u32 data)
+{
+       out_be32(base_address + (offset << 2), data);
+}
+
+/**
+ * buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter offset: The storage buffer start address.
+ * @parameter count: The number of words (32 bit) to read from the
+ *           device (ICAP).
+ **/
+static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
+               u32 offset, u32 count)
+{
+
+       s32 retries = 0;
+       void __iomem *base_address = drvdata->base_address;
+
+       if (buffer_icap_busy(base_address))
+               return -EBUSY;
+
+       if ((offset + count) > XHI_MAX_BUFFER_INTS)
+               return -EINVAL;
+
+       /* setSize count*4 to get bytes. */
+       buffer_icap_set_size(base_address, (count << 2));
+       buffer_icap_set_offset(base_address, offset);
+       buffer_icap_set_rnc(base_address, XHI_READBACK);
+
+       while (buffer_icap_busy(base_address)) {
+               retries++;
+               if (retries > XHI_MAX_RETRIES)
+                       return -EBUSY;
+       }
+       return 0;
+
+};
+
+/**
+ * buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter offset: The storage buffer start address.
+ * @parameter count: The number of words (32 bit) to read from the
+ *           device (ICAP).
+ **/
+static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
+               u32 offset, u32 count)
+{
+
+       s32 retries = 0;
+       void __iomem *base_address = drvdata->base_address;
+
+       if (buffer_icap_busy(base_address))
+               return -EBUSY;
+
+       if ((offset + count) > XHI_MAX_BUFFER_INTS)
+               return -EINVAL;
+
+       /* setSize count*4 to get bytes. */
+       buffer_icap_set_size(base_address, count << 2);
+       buffer_icap_set_offset(base_address, offset);
+       buffer_icap_set_rnc(base_address, XHI_CONFIGURE);
+
+       while (buffer_icap_busy(base_address)) {
+               retries++;
+               if (retries > XHI_MAX_RETRIES)
+                       return -EBUSY;
+       }
+       return 0;
+
+};
+
+/**
+ * buffer_icap_reset: Reset the logic of the icap device.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * Writing to the status register resets the ICAP logic in an internal
+ * version of the core.  For the version of the core published in EDK,
+ * this is a noop.
+ **/
+void buffer_icap_reset(struct hwicap_drvdata *drvdata)
+{
+    out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE);
+}
+
+/**
+ * buffer_icap_set_configuration: Load a partial bitstream from system memory.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: Kernel address of the partial bitstream.
+ * @parameter size: the size of the partial bitstream in 32 bit words.
+ **/
+int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+                            u32 size)
+{
+       int status;
+       s32 buffer_count = 0;
+       s32 num_writes = 0;
+       bool dirty = 0;
+       u32 i;
+       void __iomem *base_address = drvdata->base_address;
+
+       /* Loop through all the data */
+       for (i = 0, buffer_count = 0; i < size; i++) {
+
+               /* Copy data to bram */
+               buffer_icap_set_bram(base_address, buffer_count, data[i]);
+               dirty = 1;
+
+               if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {
+                       buffer_count++;
+                       continue;
+               }
+
+               /* Write data to ICAP */
+               status = buffer_icap_device_write(
+                               drvdata,
+                               XHI_BUFFER_START,
+                               XHI_MAX_BUFFER_INTS);
+               if (status != 0) {
+                       /* abort. */
+                       buffer_icap_reset(drvdata);
+                       return status;
+               }
+
+               buffer_count = 0;
+               num_writes++;
+               dirty = 0;
+       }
+
+       /* Write unwritten data to ICAP */
+       if (dirty) {
+               /* Write data to ICAP */
+               status = buffer_icap_device_write(drvdata, XHI_BUFFER_START,
+                                            buffer_count);
+               if (status != 0) {
+                       /* abort. */
+                       buffer_icap_reset(drvdata);
+               }
+               return status;
+       }
+
+       return 0;
+};
+
+/**
+ * buffer_icap_get_configuration: Read configuration data from the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: Address of the data representing the partial bitstream
+ * @parameter size: the size of the partial bitstream in 32 bit words.
+ **/
+int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+                            u32 size)
+{
+       int status;
+       s32 buffer_count = 0;
+       s32 read_count = 0;
+       u32 i;
+       void __iomem *base_address = drvdata->base_address;
+
+       /* Loop through all the data */
+       for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) {
+               if (buffer_count == XHI_MAX_BUFFER_INTS) {
+                       u32 words_remaining = size - i;
+                       u32 words_to_read =
+                               words_remaining <
+                               XHI_MAX_BUFFER_INTS ? words_remaining :
+                               XHI_MAX_BUFFER_INTS;
+
+                       /* Read data from ICAP */
+                       status = buffer_icap_device_read(
+                                       drvdata,
+                                       XHI_BUFFER_START,
+                                       words_to_read);
+                       if (status != 0) {
+                               /* abort. */
+                               buffer_icap_reset(drvdata);
+                               return status;
+                       }
+
+                       buffer_count = 0;
+                       read_count++;
+               }
+
+               /* Copy data from bram */
+               data[i] = buffer_icap_get_bram(base_address, buffer_count);
+               buffer_count++;
+       }
+
+       return 0;
+};
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.h b/drivers/char/xilinx_hwicap/buffer_icap.h
new file mode 100644 (file)
index 0000000..0318495
--- /dev/null
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2003-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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.
+ *
+ *****************************************************************************/
+
+#ifndef XILINX_BUFFER_ICAP_H_  /* prevent circular inclusions */
+#define XILINX_BUFFER_ICAP_H_  /* by using protection macros */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include "xilinx_hwicap.h"
+
+void buffer_icap_reset(struct hwicap_drvdata *drvdata);
+
+/* Loads a partial bitstream from system memory. */
+int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+                            u32 Size);
+
+/* Loads a partial bitstream from system memory. */
+int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+                            u32 Size);
+
+#endif
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.c b/drivers/char/xilinx_hwicap/fifo_icap.c
new file mode 100644 (file)
index 0000000..0988314
--- /dev/null
@@ -0,0 +1,381 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2007-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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 "fifo_icap.h"
+
+/* Register offsets for the XHwIcap device. */
+#define XHI_GIER_OFFSET        0x1C  /* Device Global Interrupt Enable Reg */
+#define XHI_IPISR_OFFSET 0x20  /* Interrupt Status Register */
+#define XHI_IPIER_OFFSET 0x28  /* Interrupt Enable Register */
+#define XHI_WF_OFFSET 0x100 /* Write FIFO */
+#define XHI_RF_OFFSET 0x104 /* Read FIFO */
+#define XHI_SZ_OFFSET 0x108 /* Size Register */
+#define XHI_CR_OFFSET 0x10C /* Control Register */
+#define XHI_SR_OFFSET 0x110 /* Status Register */
+#define XHI_WFV_OFFSET 0x114 /* Write FIFO Vacancy Register */
+#define XHI_RFO_OFFSET 0x118 /* Read FIFO Occupancy Register */
+
+/* Device Global Interrupt Enable Register (GIER) bit definitions */
+
+#define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */
+
+/**
+ * HwIcap Device Interrupt Status/Enable Registers
+ *
+ * Interrupt Status Register (IPISR) : This register holds the
+ * interrupt status flags for the device. These bits are toggle on
+ * write.
+ *
+ * Interrupt Enable Register (IPIER) : This register is used to enable
+ * interrupt sources for the device.
+ * Writing a '1' to a bit enables the corresponding interrupt.
+ * Writing a '0' to a bit disables the corresponding interrupt.
+ *
+ * IPISR/IPIER registers have the same bit definitions and are only defined
+ * once.
+ */
+#define XHI_IPIXR_RFULL_MASK 0x00000008 /* Read FIFO Full */
+#define XHI_IPIXR_WEMPTY_MASK 0x00000004 /* Write FIFO Empty */
+#define XHI_IPIXR_RDP_MASK 0x00000002 /* Read FIFO half full */
+#define XHI_IPIXR_WRP_MASK 0x00000001 /* Write FIFO half full */
+#define XHI_IPIXR_ALL_MASK 0x0000000F /* Mask of all interrupts */
+
+/* Control Register (CR) */
+#define XHI_CR_SW_RESET_MASK 0x00000008 /* SW Reset Mask */
+#define XHI_CR_FIFO_CLR_MASK 0x00000004 /* FIFO Clear Mask */
+#define XHI_CR_READ_MASK 0x00000002 /* Read from ICAP to FIFO */
+#define XHI_CR_WRITE_MASK 0x00000001 /* Write from FIFO to ICAP */
+
+/* Status Register (SR) */
+#define XHI_SR_CFGERR_N_MASK 0x00000100 /* Config Error Mask */
+#define XHI_SR_DALIGN_MASK 0x00000080 /* Data Alignment Mask */
+#define XHI_SR_RIP_MASK 0x00000040 /* Read back Mask */
+#define XHI_SR_IN_ABORT_N_MASK 0x00000020 /* Select Map Abort Mask */
+#define XHI_SR_DONE_MASK 0x00000001 /* Done bit Mask  */
+
+
+#define XHI_WFO_MAX_VACANCY 1024 /* Max Write FIFO Vacancy, in words */
+#define XHI_RFO_MAX_OCCUPANCY 256 /* Max Read FIFO Occupancy, in words */
+/* The maximum amount we can request from fifo_icap_get_configuration
+   at once, in bytes. */
+#define XHI_MAX_READ_TRANSACTION_WORDS 0xFFF
+
+
+/**
+ * fifo_icap_fifo_write: Write data to the write FIFO.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: the 32-bit value to be written to the FIFO.
+ *
+ * This function will silently fail if the fifo is full.
+ **/
+static inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata,
+               u32 data)
+{
+       dev_dbg(drvdata->dev, "fifo_write: %x\n", data);
+       out_be32(drvdata->base_address + XHI_WF_OFFSET, data);
+}
+
+/**
+ * fifo_icap_fifo_read: Read data from the Read FIFO.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This function will silently fail if the fifo is empty.
+ **/
+static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
+{
+       u32 data = in_be32(drvdata->base_address + XHI_RF_OFFSET);
+       dev_dbg(drvdata->dev, "fifo_read: %x\n", data);
+       return data;
+}
+
+/**
+ * fifo_icap_set_read_size: Set the the size register.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: the size of the following read transaction, in words.
+ **/
+static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata,
+               u32 data)
+{
+       out_be32(drvdata->base_address + XHI_SZ_OFFSET, data);
+}
+
+/**
+ * fifo_icap_start_config: Initiate a configuration (write) to the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ **/
+static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata)
+{
+       out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_WRITE_MASK);
+       dev_dbg(drvdata->dev, "configuration started\n");
+}
+
+/**
+ * fifo_icap_start_readback: Initiate a readback from the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ **/
+static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata)
+{
+       out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_READ_MASK);
+       dev_dbg(drvdata->dev, "readback started\n");
+}
+
+/**
+ * fifo_icap_busy: Return true if the ICAP is still processing a transaction.
+ * @parameter drvdata: a pointer to the drvdata.
+ **/
+static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
+{
+       u32 status = in_be32(drvdata->base_address + XHI_SR_OFFSET);
+       dev_dbg(drvdata->dev, "Getting status = %x\n", status);
+       return (status & XHI_SR_DONE_MASK) ? 0 : 1;
+}
+
+/**
+ * fifo_icap_write_fifo_vacancy: Query the write fifo available space.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * Return the number of words that can be safely pushed into the write fifo.
+ **/
+static inline u32 fifo_icap_write_fifo_vacancy(
+               struct hwicap_drvdata *drvdata)
+{
+       return in_be32(drvdata->base_address + XHI_WFV_OFFSET);
+}
+
+/**
+ * fifo_icap_read_fifo_occupancy: Query the read fifo available data.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * Return the number of words that can be safely read from the read fifo.
+ **/
+static inline u32 fifo_icap_read_fifo_occupancy(
+               struct hwicap_drvdata *drvdata)
+{
+       return in_be32(drvdata->base_address + XHI_RFO_OFFSET);
+}
+
+/**
+ * fifo_icap_set_configuration: Send configuration data to the ICAP.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter frame_buffer: a pointer to the data to be written to the
+ *             ICAP device.
+ * @parameter num_words: the number of words (32 bit) to write to the ICAP
+ *             device.
+
+ * This function writes the given user data to the Write FIFO in
+ * polled mode and starts the transfer of the data to
+ * the ICAP device.
+ **/
+int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,
+               u32 *frame_buffer, u32 num_words)
+{
+
+       u32 write_fifo_vacancy = 0;
+       u32 retries = 0;
+       u32 remaining_words;
+
+       dev_dbg(drvdata->dev, "fifo_set_configuration\n");
+
+       /*
+        * Check if the ICAP device is Busy with the last Read/Write
+        */
+       if (fifo_icap_busy(drvdata))
+               return -EBUSY;
+
+       /*
+        * Set up the buffer pointer and the words to be transferred.
+        */
+       remaining_words = num_words;
+
+       while (remaining_words > 0) {
+               /*
+                * Wait until we have some data in the fifo.
+                */
+               while (write_fifo_vacancy == 0) {
+                       write_fifo_vacancy =
+                               fifo_icap_write_fifo_vacancy(drvdata);
+                       retries++;
+                       if (retries > XHI_MAX_RETRIES)
+                               return -EIO;
+               }
+
+               /*
+                * Write data into the Write FIFO.
+                */
+               while ((write_fifo_vacancy != 0) &&
+                               (remaining_words > 0)) {
+                       fifo_icap_fifo_write(drvdata, *frame_buffer);
+
+                       remaining_words--;
+                       write_fifo_vacancy--;
+                       frame_buffer++;
+               }
+               /* Start pushing whatever is in the FIFO into the ICAP. */
+               fifo_icap_start_config(drvdata);
+       }
+
+       /* Wait until the write has finished. */
+       while (fifo_icap_busy(drvdata)) {
+               retries++;
+               if (retries > XHI_MAX_RETRIES)
+                       break;
+       }
+
+       dev_dbg(drvdata->dev, "done fifo_set_configuration\n");
+
+       /*
+        * If the requested number of words have not been read from
+        * the device then indicate failure.
+        */
+       if (remaining_words != 0)
+               return -EIO;
+
+       return 0;
+}
+
+/**
+ * fifo_icap_get_configuration: Read configuration data from the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: Address of the data representing the partial bitstream
+ * @parameter size: the size of the partial bitstream in 32 bit words.
+ *
+ * This function reads the specified number of words from the ICAP device in
+ * the polled mode.
+ */
+int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,
+               u32 *frame_buffer, u32 num_words)
+{
+
+       u32 read_fifo_occupancy = 0;
+       u32 retries = 0;
+       u32 *data = frame_buffer;
+       u32 remaining_words;
+       u32 words_to_read;
+
+       dev_dbg(drvdata->dev, "fifo_get_configuration\n");
+
+       /*
+        * Check if the ICAP device is Busy with the last Write/Read
+        */
+       if (fifo_icap_busy(drvdata))
+               return -EBUSY;
+
+       remaining_words = num_words;
+
+       while (remaining_words > 0) {
+               words_to_read = remaining_words;
+               /* The hardware has a limit on the number of words
+                  that can be read at one time.  */
+               if (words_to_read > XHI_MAX_READ_TRANSACTION_WORDS)
+                       words_to_read = XHI_MAX_READ_TRANSACTION_WORDS;
+
+               remaining_words -= words_to_read;
+
+               fifo_icap_set_read_size(drvdata, words_to_read);
+               fifo_icap_start_readback(drvdata);
+
+               while (words_to_read > 0) {
+                       /* Wait until we have some data in the fifo. */
+                       while (read_fifo_occupancy == 0) {
+                               read_fifo_occupancy =
+                                       fifo_icap_read_fifo_occupancy(drvdata);
+                               retries++;
+                               if (retries > XHI_MAX_RETRIES)
+                                       return -EIO;
+                       }
+
+                       if (read_fifo_occupancy > words_to_read)
+                               read_fifo_occupancy = words_to_read;
+
+                       words_to_read -= read_fifo_occupancy;
+
+                       /* Read the data from the Read FIFO. */
+                       while (read_fifo_occupancy != 0) {
+                               *data++ = fifo_icap_fifo_read(drvdata);
+                               read_fifo_occupancy--;
+                       }
+               }
+       }
+
+       dev_dbg(drvdata->dev, "done fifo_get_configuration\n");
+
+       return 0;
+}
+
+/**
+ * buffer_icap_reset: Reset the logic of the icap device.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This function forces the software reset of the complete HWICAP device.
+ * All the registers will return to the default value and the FIFO is also
+ * flushed as a part of this software reset.
+ */
+void fifo_icap_reset(struct hwicap_drvdata *drvdata)
+{
+       u32 reg_data;
+       /*
+        * Reset the device by setting/clearing the RESET bit in the
+        * Control Register.
+        */
+       reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
+
+       out_be32(drvdata->base_address + XHI_CR_OFFSET,
+                               reg_data | XHI_CR_SW_RESET_MASK);
+
+       out_be32(drvdata->base_address + XHI_CR_OFFSET,
+                               reg_data & (~XHI_CR_SW_RESET_MASK));
+
+}
+
+/**
+ * fifo_icap_flush_fifo: This function flushes the FIFOs in the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ */
+void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata)
+{
+       u32 reg_data;
+       /*
+        * Flush the FIFO by setting/clearing the FIFO Clear bit in the
+        * Control Register.
+        */
+       reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
+
+       out_be32(drvdata->base_address + XHI_CR_OFFSET,
+                               reg_data | XHI_CR_FIFO_CLR_MASK);
+
+       out_be32(drvdata->base_address + XHI_CR_OFFSET,
+                               reg_data & (~XHI_CR_FIFO_CLR_MASK));
+}
+
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.h b/drivers/char/xilinx_hwicap/fifo_icap.h
new file mode 100644 (file)
index 0000000..4d3068d
--- /dev/null
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2007-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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.
+ *
+ *****************************************************************************/
+
+#ifndef XILINX_FIFO_ICAP_H_    /* prevent circular inclusions */
+#define XILINX_FIFO_ICAP_H_    /* by using protection macros */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include "xilinx_hwicap.h"
+
+/* Reads integers from the device into the storage buffer. */
+int fifo_icap_get_configuration(
+               struct hwicap_drvdata *drvdata,
+               u32 *FrameBuffer,
+               u32 NumWords);
+
+/* Writes integers to the device from the storage buffer. */
+int fifo_icap_set_configuration(
+               struct hwicap_drvdata *drvdata,
+               u32 *FrameBuffer,
+               u32 NumWords);
+
+void fifo_icap_reset(struct hwicap_drvdata *drvdata);
+void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata);
+
+#endif
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
new file mode 100644 (file)
index 0000000..24f6aef
--- /dev/null
@@ -0,0 +1,904 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2002 Xilinx Inc., Systems Engineering Group
+ *     (c) Copyright 2004 Xilinx Inc., Systems Engineering Group
+ *     (c) Copyright 2007-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+
+/*
+ * This is the code behind /dev/xilinx_icap -- it allows a user-space
+ * application to use the Xilinx ICAP subsystem.
+ *
+ * The following operations are possible:
+ *
+ * open         open the port and initialize for access.
+ * release      release port
+ * write        Write a bitstream to the configuration processor.
+ * read         Read a data stream from the configuration processor.
+ *
+ * After being opened, the port is initialized and accessed to avoid a
+ * corrupted first read which may occur with some hardware.  The port
+ * is left in a desynched state, requiring that a synch sequence be
+ * transmitted before any valid configuration data.  A user will have
+ * exclusive access to the device while it remains open, and the state
+ * of the ICAP cannot be guaranteed after the device is closed.  Note
+ * that a complete reset of the core and the state of the ICAP cannot
+ * be performed on many versions of the cores, hence users of this
+ * device should avoid making inconsistent accesses to the device.  In
+ * particular, accessing the read interface, without first generating
+ * a write containing a readback packet can leave the ICAP in an
+ * inaccessible state.
+ *
+ * Note that in order to use the read interface, it is first necessary
+ * to write a request packet to the write interface.  i.e., it is not
+ * possible to simply readback the bitstream (or any configuration
+ * bits) from a device without specifically requesting them first.
+ * The code to craft such packets is intended to be part of the
+ * user-space application code that uses this device.  The simplest
+ * way to use this interface is simply:
+ *
+ * cp foo.bit /dev/xilinx_icap
+ *
+ * Note that unless foo.bit is an appropriately constructed partial
+ * bitstream, this has a high likelyhood of overwriting the design
+ * currently programmed in the FPGA.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <asm/semaphore.h>
+#include <linux/sysctl.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_OF
+/* For open firmware. */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
+
+#include "xilinx_hwicap.h"
+#include "buffer_icap.h"
+#include "fifo_icap.h"
+
+#define DRIVER_NAME "xilinx_icap"
+
+#define HWICAP_REGS   (0x10000)
+
+/* dynamically allocate device number */
+static int xhwicap_major;
+static int xhwicap_minor;
+#define HWICAP_DEVICES 1
+
+module_param(xhwicap_major, int, S_IRUGO);
+module_param(xhwicap_minor, int, S_IRUGO);
+
+/* An array, which is set to true when the device is registered. */
+static bool probed_devices[HWICAP_DEVICES];
+
+static struct class *icap_class;
+
+#define UNIMPLEMENTED 0xFFFF
+
+static const struct config_registers v2_config_registers = {
+       .CRC = 0,
+       .FAR = 1,
+       .FDRI = 2,
+       .FDRO = 3,
+       .CMD = 4,
+       .CTL = 5,
+       .MASK = 6,
+       .STAT = 7,
+       .LOUT = 8,
+       .COR = 9,
+       .MFWR = 10,
+       .FLR = 11,
+       .KEY = 12,
+       .CBC = 13,
+       .IDCODE = 14,
+       .AXSS = UNIMPLEMENTED,
+       .C0R_1 = UNIMPLEMENTED,
+       .CSOB = UNIMPLEMENTED,
+       .WBSTAR = UNIMPLEMENTED,
+       .TIMER = UNIMPLEMENTED,
+       .BOOTSTS = UNIMPLEMENTED,
+       .CTL_1 = UNIMPLEMENTED,
+};
+
+static const struct config_registers v4_config_registers = {
+       .CRC = 0,
+       .FAR = 1,
+       .FDRI = 2,
+       .FDRO = 3,
+       .CMD = 4,
+       .CTL = 5,
+       .MASK = 6,
+       .STAT = 7,
+       .LOUT = 8,
+       .COR = 9,
+       .MFWR = 10,
+       .FLR = UNIMPLEMENTED,
+       .KEY = UNIMPLEMENTED,
+       .CBC = 11,
+       .IDCODE = 12,
+       .AXSS = 13,
+       .C0R_1 = UNIMPLEMENTED,
+       .CSOB = UNIMPLEMENTED,
+       .WBSTAR = UNIMPLEMENTED,
+       .TIMER = UNIMPLEMENTED,
+       .BOOTSTS = UNIMPLEMENTED,
+       .CTL_1 = UNIMPLEMENTED,
+};
+static const struct config_registers v5_config_registers = {
+       .CRC = 0,
+       .FAR = 1,
+       .FDRI = 2,
+       .FDRO = 3,
+       .CMD = 4,
+       .CTL = 5,
+       .MASK = 6,
+       .STAT = 7,
+       .LOUT = 8,
+       .COR = 9,
+       .MFWR = 10,
+       .FLR = UNIMPLEMENTED,
+       .KEY = UNIMPLEMENTED,
+       .CBC = 11,
+       .IDCODE = 12,
+       .AXSS = 13,
+       .C0R_1 = 14,
+       .CSOB = 15,
+       .WBSTAR = 16,
+       .TIMER = 17,
+       .BOOTSTS = 18,
+       .CTL_1 = 19,
+};
+
+/**
+ * hwicap_command_desync: Send a DESYNC command to the ICAP port.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This command desynchronizes the ICAP After this command, a
+ * bitstream containing a NULL packet, followed by a SYNCH packet is
+ * required before the ICAP will recognize commands.
+ */
+int hwicap_command_desync(struct hwicap_drvdata *drvdata)
+{
+       u32 buffer[4];
+       u32 index = 0;
+
+       /*
+        * Create the data to be written to the ICAP.
+        */
+       buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
+       buffer[index++] = XHI_CMD_DESYNCH;
+       buffer[index++] = XHI_NOOP_PACKET;
+       buffer[index++] = XHI_NOOP_PACKET;
+
+       /*
+        * Write the data to the FIFO and intiate the transfer of data present
+        * in the FIFO to the ICAP device.
+        */
+       return drvdata->config->set_configuration(drvdata,
+                       &buffer[0], index);
+}
+
+/**
+ * hwicap_command_capture: Send a CAPTURE command to the ICAP port.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This command captures all of the flip flop states so they will be
+ * available during readback.  One can use this command instead of
+ * enabling the CAPTURE block in the design.
+ */
+int hwicap_command_capture(struct hwicap_drvdata *drvdata)
+{
+       u32 buffer[7];
+       u32 index = 0;
+
+       /*
+        * Create the data to be written to the ICAP.
+        */
+       buffer[index++] = XHI_DUMMY_PACKET;
+       buffer[index++] = XHI_SYNC_PACKET;
+       buffer[index++] = XHI_NOOP_PACKET;
+       buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
+       buffer[index++] = XHI_CMD_GCAPTURE;
+       buffer[index++] = XHI_DUMMY_PACKET;
+       buffer[index++] = XHI_DUMMY_PACKET;
+
+       /*
+        * Write the data to the FIFO and intiate the transfer of data
+        * present in the FIFO to the ICAP device.
+        */
+       return drvdata->config->set_configuration(drvdata,
+                       &buffer[0], index);
+
+}
+
+/**
+ * hwicap_get_configuration_register: Query a configuration register.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter reg: a constant which represents the configuration
+ *             register value to be returned.
+ *             Examples:  XHI_IDCODE, XHI_FLR.
+ * @parameter RegData: returns the value of the register.
+ *
+ * Sends a query packet to the ICAP and then receives the response.
+ * The icap is left in Synched state.
+ */
+int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
+               u32 reg, u32 *RegData)
+{
+       int status;
+       u32 buffer[6];
+       u32 index = 0;
+
+       /*
+        * Create the data to be written to the ICAP.
+        */
+       buffer[index++] = XHI_DUMMY_PACKET;
+       buffer[index++] = XHI_SYNC_PACKET;
+       buffer[index++] = XHI_NOOP_PACKET;
+       buffer[index++] = hwicap_type_1_read(reg) | 1;
+       buffer[index++] = XHI_NOOP_PACKET;
+       buffer[index++] = XHI_NOOP_PACKET;
+
+       /*
+        * Write the data to the FIFO and intiate the transfer of data present
+        * in the FIFO to the ICAP device.
+        */
+       status = drvdata->config->set_configuration(drvdata,
+                       &buffer[0], index);
+       if (status)
+               return status;
+
+       /*
+        * Read the configuration register
+        */
+       status = drvdata->config->get_configuration(drvdata, RegData, 1);
+       if (status)
+               return status;
+
+       return 0;
+}
+
+int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)
+{
+       int status;
+       u32 idcode;
+
+       dev_dbg(drvdata->dev, "initializing\n");
+
+       /* Abort any current transaction, to make sure we have the
+        * ICAP in a good state. */
+       dev_dbg(drvdata->dev, "Reset...\n");
+       drvdata->config->reset(drvdata);
+
+       dev_dbg(drvdata->dev, "Desync...\n");
+       status = hwicap_command_desync(drvdata);
+       if (status)
+               return status;
+
+       /* Attempt to read the IDCODE from ICAP.  This
+        * may not be returned correctly, due to the design of the
+        * hardware.
+        */
+       dev_dbg(drvdata->dev, "Reading IDCODE...\n");
+       status = hwicap_get_configuration_register(
+                       drvdata, drvdata->config_regs->IDCODE, &idcode);
+       dev_dbg(drvdata->dev, "IDCODE = %x\n", idcode);
+       if (status)
+               return status;
+
+       dev_dbg(drvdata->dev, "Desync...\n");
+       status = hwicap_command_desync(drvdata);
+       if (status)
+               return status;
+
+       return 0;
+}
+
+static ssize_t
+hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+       struct hwicap_drvdata *drvdata = file->private_data;
+       ssize_t bytes_to_read = 0;
+       u32 *kbuf;
+       u32 words;
+       u32 bytes_remaining;
+       int status;
+
+       if (down_interruptible(&drvdata->sem))
+               return -ERESTARTSYS;
+
+       if (drvdata->read_buffer_in_use) {
+               /* If there are leftover bytes in the buffer, just */
+               /* return them and don't try to read more from the */
+               /* ICAP device. */
+               bytes_to_read =
+                       (count < drvdata->read_buffer_in_use) ? count :
+                       drvdata->read_buffer_in_use;
+
+               /* Return the data currently in the read buffer. */
+               if (copy_to_user(buf, drvdata->read_buffer, bytes_to_read)) {
+                       status = -EFAULT;
+                       goto error;
+               }
+               drvdata->read_buffer_in_use -= bytes_to_read;
+               memcpy(drvdata->read_buffer + bytes_to_read,
+                               drvdata->read_buffer, 4 - bytes_to_read);
+       } else {
+               /* Get new data from the ICAP, and return was was requested. */
+               kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);
+               if (!kbuf) {
+                       status = -ENOMEM;
+                       goto error;
+               }
+
+               /* The ICAP device is only able to read complete */
+               /* words.  If a number of bytes that do not correspond */
+               /* to complete words is requested, then we read enough */
+               /* words to get the required number of bytes, and then */
+               /* save the remaining bytes for the next read. */
+
+               /* Determine the number of words to read, rounding up */
+               /* if necessary. */
+               words = ((count + 3) >> 2);
+               bytes_to_read = words << 2;
+
+               if (bytes_to_read > PAGE_SIZE)
+                       bytes_to_read = PAGE_SIZE;
+
+               /* Ensure we only read a complete number of words. */
+               bytes_remaining = bytes_to_read & 3;
+               bytes_to_read &= ~3;
+               words = bytes_to_read >> 2;
+
+               status = drvdata->config->get_configuration(drvdata,
+                               kbuf, words);
+
+               /* If we didn't read correctly, then bail out. */
+               if (status) {
+                       free_page((unsigned long)kbuf);
+                       goto error;
+               }
+
+               /* If we fail to return the data to the user, then bail out. */
+               if (copy_to_user(buf, kbuf, bytes_to_read)) {
+                       free_page((unsigned long)kbuf);
+                       status = -EFAULT;
+                       goto error;
+               }
+               memcpy(kbuf, drvdata->read_buffer, bytes_remaining);
+               drvdata->read_buffer_in_use = bytes_remaining;
+               free_page((unsigned long)kbuf);
+       }
+       status = bytes_to_read;
+ error:
+       up(&drvdata->sem);
+       return status;
+}
+
+static ssize_t
+hwicap_write(struct file *file, const char *buf,
+               size_t count, loff_t *ppos)
+{
+       struct hwicap_drvdata *drvdata = file->private_data;
+       ssize_t written = 0;
+       ssize_t left = count;
+       u32 *kbuf;
+       ssize_t len;
+       ssize_t status;
+
+       if (down_interruptible(&drvdata->sem))
+               return -ERESTARTSYS;
+
+       left += drvdata->write_buffer_in_use;
+
+       /* Only write multiples of 4 bytes. */
+       if (left < 4) {
+               status = 0;
+               goto error;
+       }
+
+       kbuf = (u32 *) __get_free_page(GFP_KERNEL);
+       if (!kbuf) {
+               status = -ENOMEM;
+               goto error;
+       }
+
+       while (left > 3) {
+               /* only write multiples of 4 bytes, so there might */
+               /* be as many as 3 bytes left (at the end). */
+               len = left;
+
+               if (len > PAGE_SIZE)
+                       len = PAGE_SIZE;
+               len &= ~3;
+
+               if (drvdata->write_buffer_in_use) {
+                       memcpy(kbuf, drvdata->write_buffer,
+                                       drvdata->write_buffer_in_use);
+                       if (copy_from_user(
+                           (((char *)kbuf) + (drvdata->write_buffer_in_use)),
+                           buf + written,
+                           len - (drvdata->write_buffer_in_use))) {
+                               free_page((unsigned long)kbuf);
+                               status = -EFAULT;
+                               goto error;
+                       }
+               } else {
+                       if (copy_from_user(kbuf, buf + written, len)) {
+                               free_page((unsigned long)kbuf);
+                               status = -EFAULT;
+                               goto error;
+                       }
+               }
+
+               status = drvdata->config->set_configuration(drvdata,
+                               kbuf, len >> 2);
+
+               if (status) {
+                       free_page((unsigned long)kbuf);
+                       status = -EFAULT;
+                       goto error;
+               }
+               if (drvdata->write_buffer_in_use) {
+                       len -= drvdata->write_buffer_in_use;
+                       left -= drvdata->write_buffer_in_use;
+                       drvdata->write_buffer_in_use = 0;
+               }
+               written += len;
+               left -= len;
+       }
+       if ((left > 0) && (left < 4)) {
+               if (!copy_from_user(drvdata->write_buffer,
+                                               buf + written, left)) {
+                       drvdata->write_buffer_in_use = left;
+                       written += left;
+                       left = 0;
+               }
+       }
+
+       free_page((unsigned long)kbuf);
+       status = written;
+ error:
+       up(&drvdata->sem);
+       return status;
+}
+
+static int hwicap_open(struct inode *inode, struct file *file)
+{
+       struct hwicap_drvdata *drvdata;
+       int status;
+
+       drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);
+
+       if (down_interruptible(&drvdata->sem))
+               return -ERESTARTSYS;
+
+       if (drvdata->is_open) {
+               status = -EBUSY;
+               goto error;
+       }
+
+       status = hwicap_initialize_hwicap(drvdata);
+       if (status) {
+               dev_err(drvdata->dev, "Failed to open file");
+               goto error;
+       }
+
+       file->private_data = drvdata;
+       drvdata->write_buffer_in_use = 0;
+       drvdata->read_buffer_in_use = 0;
+       drvdata->is_open = 1;
+
+ error:
+       up(&drvdata->sem);
+       return status;
+}
+
+static int hwicap_release(struct inode *inode, struct file *file)
+{
+       struct hwicap_drvdata *drvdata = file->private_data;
+       int i;
+       int status = 0;
+
+       if (down_interruptible(&drvdata->sem))
+               return -ERESTARTSYS;
+
+       if (drvdata->write_buffer_in_use) {
+               /* Flush write buffer. */
+               for (i = drvdata->write_buffer_in_use; i < 4; i++)
+                       drvdata->write_buffer[i] = 0;
+
+               status = drvdata->config->set_configuration(drvdata,
+                               (u32 *) drvdata->write_buffer, 1);
+               if (status)
+                       goto error;
+       }
+
+       status = hwicap_command_desync(drvdata);
+       if (status)
+               goto error;
+
+ error:
+       drvdata->is_open = 0;
+       up(&drvdata->sem);
+       return status;
+}
+
+static struct file_operations hwicap_fops = {
+       .owner = THIS_MODULE,
+       .write = hwicap_write,
+       .read = hwicap_read,
+       .open = hwicap_open,
+       .release = hwicap_release,
+};
+
+static int __devinit hwicap_setup(struct device *dev, int id,
+               const struct resource *regs_res,
+               const struct hwicap_driver_config *config,
+               const struct config_registers *config_regs)
+{
+       dev_t devt;
+       struct hwicap_drvdata *drvdata = NULL;
+       int retval = 0;
+
+       dev_info(dev, "Xilinx icap port driver\n");
+
+       if (id < 0) {
+               for (id = 0; id < HWICAP_DEVICES; id++)
+                       if (!probed_devices[id])
+                               break;
+       }
+       if (id < 0 || id >= HWICAP_DEVICES) {
+               dev_err(dev, "%s%i too large\n", DRIVER_NAME, id);
+               return -EINVAL;
+       }
+       if (probed_devices[id]) {
+               dev_err(dev, "cannot assign to %s%i; it is already in use\n",
+                       DRIVER_NAME, id);
+               return -EBUSY;
+       }
+
+       probed_devices[id] = 1;
+
+       devt = MKDEV(xhwicap_major, xhwicap_minor + id);
+
+       drvdata = kmalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL);
+       if (!drvdata) {
+               dev_err(dev, "Couldn't allocate device private record\n");
+               return -ENOMEM;
+       }
+       memset((void *)drvdata, 0, sizeof(struct hwicap_drvdata));
+       dev_set_drvdata(dev, (void *)drvdata);
+
+       if (!regs_res) {
+               dev_err(dev, "Couldn't get registers resource\n");
+               retval = -EFAULT;
+               goto failed1;
+       }
+
+       drvdata->mem_start = regs_res->start;
+       drvdata->mem_end = regs_res->end;
+       drvdata->mem_size = regs_res->end - regs_res->start + 1;
+
+       if (!request_mem_region(drvdata->mem_start,
+                                       drvdata->mem_size, DRIVER_NAME)) {
+               dev_err(dev, "Couldn't lock memory region at %p\n",
+                       (void *)regs_res->start);
+               retval = -EBUSY;
+               goto failed1;
+       }
+
+       drvdata->devt = devt;
+       drvdata->dev = dev;
+       drvdata->base_address = ioremap(drvdata->mem_start, drvdata->mem_size);
+       if (!drvdata->base_address) {
+               dev_err(dev, "ioremap() failed\n");
+               goto failed2;
+       }
+
+       drvdata->config = config;
+       drvdata->config_regs = config_regs;
+
+       init_MUTEX(&drvdata->sem);
+       drvdata->is_open = 0;
+
+       dev_info(dev, "ioremap %lx to %p with size %x\n",
+                (unsigned long int)drvdata->mem_start,
+                       drvdata->base_address, drvdata->mem_size);
+
+       cdev_init(&drvdata->cdev, &hwicap_fops);
+       drvdata->cdev.owner = THIS_MODULE;
+       retval = cdev_add(&drvdata->cdev, devt, 1);
+       if (retval) {
+               dev_err(dev, "cdev_add() failed\n");
+               goto failed3;
+       }
+       /*  devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */
+       class_device_create(icap_class, NULL, devt, NULL, DRIVER_NAME);
+       return 0;               /* success */
+
+ failed3:
+       iounmap(drvdata->base_address);
+
+ failed2:
+       release_mem_region(regs_res->start, drvdata->mem_size);
+
+ failed1:
+       kfree(drvdata);
+
+       return retval;
+}
+
+static struct hwicap_driver_config buffer_icap_config = {
+       .get_configuration = buffer_icap_get_configuration,
+       .set_configuration = buffer_icap_set_configuration,
+       .reset = buffer_icap_reset,
+};
+
+static struct hwicap_driver_config fifo_icap_config = {
+       .get_configuration = fifo_icap_get_configuration,
+       .set_configuration = fifo_icap_set_configuration,
+       .reset = fifo_icap_reset,
+};
+
+static int __devexit hwicap_remove(struct device *dev)
+{
+       struct hwicap_drvdata *drvdata;
+
+       drvdata = (struct hwicap_drvdata *)dev_get_drvdata(dev);
+
+       if (!drvdata)
+               return 0;
+
+       class_device_destroy(icap_class, drvdata->devt);
+       cdev_del(&drvdata->cdev);
+       iounmap(drvdata->base_address);
+       release_mem_region(drvdata->mem_start, drvdata->mem_size);
+       kfree(drvdata);
+       dev_set_drvdata(dev, NULL);
+       probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0;
+
+       return 0;               /* success */
+}
+
+static int __devinit hwicap_drv_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       const struct config_registers *regs;
+       const char *family;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       /* It's most likely that we're using V4, if the family is not
+          specified */
+       regs = &v4_config_registers;
+       family = pdev->dev.platform_data;
+
+       if (family) {
+               if (!strcmp(family, "virtex2p")) {
+                       regs = &v2_config_registers;
+               } else if (!strcmp(family, "virtex4")) {
+                       regs = &v4_config_registers;
+               } else if (!strcmp(family, "virtex5")) {
+                       regs = &v5_config_registers;
+               }
+       }
+
+       return hwicap_setup(&pdev->dev, pdev->id, res,
+                       &buffer_icap_config, regs);
+}
+
+static int __devexit hwicap_drv_remove(struct platform_device *pdev)
+{
+       return hwicap_remove(&pdev->dev);
+}
+
+static struct platform_driver hwicap_platform_driver = {
+       .probe = hwicap_drv_probe,
+       .remove = hwicap_drv_remove,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = DRIVER_NAME,
+       },
+};
+
+/* ---------------------------------------------------------------------
+ * OF bus binding
+ */
+
+#if defined(CONFIG_OF)
+static int __devinit
+hwicap_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+       struct resource res;
+       const unsigned int *id;
+       const char *family;
+       int rc;
+       const struct hwicap_driver_config *config = match->data;
+       const struct config_registers *regs;
+
+       dev_dbg(&op->dev, "hwicap_of_probe(%p, %p)\n", op, match);
+
+       rc = of_address_to_resource(op->node, 0, &res);
+       if (rc) {
+               dev_err(&op->dev, "invalid address\n");
+               return rc;
+       }
+
+       id = of_get_property(op->node, "port-number", NULL);
+
+       /* It's most likely that we're using V4, if the family is not
+          specified */
+       regs = &v4_config_registers;
+       family = of_get_property(op->node, "xlnx,family", NULL);
+
+       if (family) {
+               if (!strcmp(family, "virtex2p")) {
+                       regs = &v2_config_registers;
+               } else if (!strcmp(family, "virtex4")) {
+                       regs = &v4_config_registers;
+               } else if (!strcmp(family, "virtex5")) {
+                       regs = &v5_config_registers;
+               }
+       }
+       return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
+                       regs);
+}
+
+static int __devexit hwicap_of_remove(struct of_device *op)
+{
+       return hwicap_remove(&op->dev);
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id __devinit hwicap_of_match[] = {
+       { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config},
+       { .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config},
+       {},
+};
+MODULE_DEVICE_TABLE(of, hwicap_of_match);
+
+static struct of_platform_driver hwicap_of_driver = {
+       .owner = THIS_MODULE,
+       .name = DRIVER_NAME,
+       .match_table = hwicap_of_match,
+       .probe = hwicap_of_probe,
+       .remove = __devexit_p(hwicap_of_remove),
+       .driver = {
+               .name = DRIVER_NAME,
+       },
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __devinit hwicap_of_register(void)
+{
+       pr_debug("hwicap: calling of_register_platform_driver()\n");
+       return of_register_platform_driver(&hwicap_of_driver);
+}
+
+static inline void __devexit hwicap_of_unregister(void)
+{
+       of_unregister_platform_driver(&hwicap_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __devinit hwicap_of_register(void) { return 0; }
+static inline void __devexit hwicap_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+static int __devinit hwicap_module_init(void)
+{
+       dev_t devt;
+       int retval;
+
+       icap_class = class_create(THIS_MODULE, "xilinx_config");
+
+       if (xhwicap_major) {
+               devt = MKDEV(xhwicap_major, xhwicap_minor);
+               retval = register_chrdev_region(
+                               devt,
+                               HWICAP_DEVICES,
+                               DRIVER_NAME);
+               if (retval < 0)
+                       return retval;
+       } else {
+               retval = alloc_chrdev_region(&devt,
+                               xhwicap_minor,
+                               HWICAP_DEVICES,
+                               DRIVER_NAME);
+               if (retval < 0)
+                       return retval;
+               xhwicap_major = MAJOR(devt);
+       }
+
+       retval = platform_driver_register(&hwicap_platform_driver);
+
+       if (retval)
+               goto failed1;
+
+       retval = hwicap_of_register();
+
+       if (retval)
+               goto failed2;
+
+       return retval;
+
+ failed2:
+       platform_driver_unregister(&hwicap_platform_driver);
+
+ failed1:
+       unregister_chrdev_region(devt, HWICAP_DEVICES);
+
+       return retval;
+}
+
+static void __devexit hwicap_module_cleanup(void)
+{
+       dev_t devt = MKDEV(xhwicap_major, xhwicap_minor);
+
+       class_destroy(icap_class);
+
+       platform_driver_unregister(&hwicap_platform_driver);
+
+       hwicap_of_unregister();
+
+       unregister_chrdev_region(devt, HWICAP_DEVICES);
+}
+
+module_init(hwicap_module_init);
+module_exit(hwicap_module_cleanup);
+
+MODULE_AUTHOR("Xilinx, Inc; Xilinx Research Labs Group");
+MODULE_DESCRIPTION("Xilinx ICAP Port Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
new file mode 100644 (file)
index 0000000..ae771ca
--- /dev/null
@@ -0,0 +1,193 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2003-2007 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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.
+ *
+ *****************************************************************************/
+
+#ifndef XILINX_HWICAP_H_       /* prevent circular inclusions */
+#define XILINX_HWICAP_H_       /* by using protection macros */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+struct hwicap_drvdata {
+       u32 write_buffer_in_use;  /* Always in [0,3] */
+       u8 write_buffer[4];
+       u32 read_buffer_in_use;   /* Always in [0,3] */
+       u8 read_buffer[4];
+       u32 mem_start;            /* phys. address of the control registers */
+       u32 mem_end;              /* phys. address of the control registers */
+       u32 mem_size;
+       void __iomem *base_address;/* virt. address of the control registers */
+
+       struct device *dev;
+       struct cdev cdev;       /* Char device structure */
+       dev_t devt;
+
+       const struct hwicap_driver_config *config;
+       const struct config_registers *config_regs;
+       void *private_data;
+       bool is_open;
+       struct semaphore sem;
+};
+
+struct hwicap_driver_config {
+       int (*get_configuration)(struct hwicap_drvdata *drvdata, u32 *data,
+                       u32 size);
+       int (*set_configuration)(struct hwicap_drvdata *drvdata, u32 *data,
+                       u32 size);
+       void (*reset)(struct hwicap_drvdata *drvdata);
+};
+
+/* Number of times to poll the done regsiter */
+#define XHI_MAX_RETRIES     10
+
+/************ Constant Definitions *************/
+
+#define XHI_PAD_FRAMES              0x1
+
+/* Mask for calculating configuration packet headers */
+#define XHI_WORD_COUNT_MASK_TYPE_1  0x7FFUL
+#define XHI_WORD_COUNT_MASK_TYPE_2  0x1FFFFFUL
+#define XHI_TYPE_MASK               0x7
+#define XHI_REGISTER_MASK           0xF
+#define XHI_OP_MASK                 0x3
+
+#define XHI_TYPE_SHIFT              29
+#define XHI_REGISTER_SHIFT          13
+#define XHI_OP_SHIFT                27
+
+#define XHI_TYPE_1                  1
+#define XHI_TYPE_2                  2
+#define XHI_OP_WRITE                2
+#define XHI_OP_READ                 1
+
+/* Address Block Types */
+#define XHI_FAR_CLB_BLOCK           0
+#define XHI_FAR_BRAM_BLOCK          1
+#define XHI_FAR_BRAM_INT_BLOCK      2
+
+struct config_registers {
+       u32 CRC;
+       u32 FAR;
+       u32 FDRI;
+       u32 FDRO;
+       u32 CMD;
+       u32 CTL;
+       u32 MASK;
+       u32 STAT;
+       u32 LOUT;
+       u32 COR;
+       u32 MFWR;
+       u32 FLR;
+       u32 KEY;
+       u32 CBC;
+       u32 IDCODE;
+       u32 AXSS;
+       u32 C0R_1;
+       u32 CSOB;
+       u32 WBSTAR;
+       u32 TIMER;
+       u32 BOOTSTS;
+       u32 CTL_1;
+};
+
+/* Configuration Commands */
+#define XHI_CMD_NULL                0
+#define XHI_CMD_WCFG                1
+#define XHI_CMD_MFW                 2
+#define XHI_CMD_DGHIGH              3
+#define XHI_CMD_RCFG                4
+#define XHI_CMD_START               5
+#define XHI_CMD_RCAP                6
+#define XHI_CMD_RCRC                7
+#define XHI_CMD_AGHIGH              8
+#define XHI_CMD_SWITCH              9
+#define XHI_CMD_GRESTORE            10
+#define XHI_CMD_SHUTDOWN            11
+#define XHI_CMD_GCAPTURE            12
+#define XHI_CMD_DESYNCH             13
+#define XHI_CMD_IPROG               15 /* Only in Virtex5 */
+#define XHI_CMD_CRCC                16 /* Only in Virtex5 */
+#define XHI_CMD_LTIMER              17 /* Only in Virtex5 */
+
+/* Packet constants */
+#define XHI_SYNC_PACKET             0xAA995566UL
+#define XHI_DUMMY_PACKET            0xFFFFFFFFUL
+#define XHI_NOOP_PACKET             (XHI_TYPE_1 << XHI_TYPE_SHIFT)
+#define XHI_TYPE_2_READ ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
+                       (XHI_OP_READ << XHI_OP_SHIFT))
+
+#define XHI_TYPE_2_WRITE ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
+                       (XHI_OP_WRITE << XHI_OP_SHIFT))
+
+#define XHI_TYPE2_CNT_MASK          0x07FFFFFF
+
+#define XHI_TYPE_1_PACKET_MAX_WORDS 2047UL
+#define XHI_TYPE_1_HEADER_BYTES     4
+#define XHI_TYPE_2_HEADER_BYTES     8
+
+/* Constant to use for CRC check when CRC has been disabled */
+#define XHI_DISABLED_AUTO_CRC       0x0000DEFCUL
+
+/**
+ * hwicap_type_1_read: Generates a Type 1 read packet header.
+ * @parameter: Register is the address of the register to be read back.
+ *
+ * Generates a Type 1 read packet header, which is used to indirectly
+ * read registers in the configuration logic.  This packet must then
+ * be sent through the icap device, and a return packet received with
+ * the information.
+ **/
+static inline u32 hwicap_type_1_read(u32 Register)
+{
+       return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
+               (Register << XHI_REGISTER_SHIFT) |
+               (XHI_OP_READ << XHI_OP_SHIFT);
+}
+
+/**
+ * hwicap_type_1_write: Generates a Type 1 write packet header
+ * @parameter: Register is the address of the register to be read back.
+ **/
+static inline u32 hwicap_type_1_write(u32 Register)
+{
+       return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
+               (Register << XHI_REGISTER_SHIFT) |
+               (XHI_OP_WRITE << XHI_OP_SHIFT);
+}
+
+#endif
index 721f86f4f0085d3a4caf11c7365ae18643825c84..c159ae64eeb2cf791d8aa36036e0480b8d3cf487 100644 (file)
@@ -9,9 +9,6 @@ config CPU_FREQ
          clock speed, you need to either enable a dynamic cpufreq governor
          (see below) after boot, or use a userspace tool.
 
-         To compile this driver as a module, choose M here: the
-         module will be called cpufreq.
-
          For details, take a look at <file:Documentation/cpu-freq>.
 
          If in doubt, say N.
index b730d670952957871f2eecf3f35989e673c70855..64926aa990dbc024b46aeaca71c76c8d7a1ee7a5 100644 (file)
@@ -287,7 +287,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
        if (!l_p_j_ref_freq) {
                l_p_j_ref = loops_per_jiffy;
                l_p_j_ref_freq = ci->old;
-               dprintk("saving %lu as reference value for loops_per_jiffy;"
+               dprintk("saving %lu as reference value for loops_per_jiffy; "
                        "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
        }
        if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
@@ -295,7 +295,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
            (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
                loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
                                                                ci->new);
-               dprintk("scaling loops_per_jiffy to %lu"
+               dprintk("scaling loops_per_jiffy to %lu "
                        "for frequency %u kHz\n", loops_per_jiffy, ci->new);
        }
 }
@@ -601,6 +601,31 @@ static ssize_t show_affected_cpus (struct cpufreq_policy * policy, char *buf)
        return i;
 }
 
+static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
+               const char *buf, size_t count)
+{
+       unsigned int freq = 0;
+       unsigned int ret;
+
+       if (!policy->governor->store_setspeed)
+               return -EINVAL;
+
+       ret = sscanf(buf, "%u", &freq);
+       if (ret != 1)
+               return -EINVAL;
+
+       policy->governor->store_setspeed(policy, freq);
+
+       return count;
+}
+
+static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
+{
+       if (!policy->governor->show_setspeed)
+               return sprintf(buf, "<unsupported>\n");
+
+       return policy->governor->show_setspeed(policy, buf);
+}
 
 #define define_one_ro(_name) \
 static struct freq_attr _name = \
@@ -624,6 +649,7 @@ define_one_ro(affected_cpus);
 define_one_rw(scaling_min_freq);
 define_one_rw(scaling_max_freq);
 define_one_rw(scaling_governor);
+define_one_rw(scaling_setspeed);
 
 static struct attribute * default_attrs[] = {
        &cpuinfo_min_freq.attr,
@@ -634,6 +660,7 @@ static struct attribute * default_attrs[] = {
        &scaling_governor.attr,
        &scaling_driver.attr,
        &scaling_available_governors.attr,
+       &scaling_setspeed.attr,
        NULL
 };
 
@@ -1313,7 +1340,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
                        struct cpufreq_freqs freqs;
 
                        if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
-                               dprintk("Warning: CPU frequency"
+                               dprintk("Warning: CPU frequency "
                                       "is %u, cpufreq assumed %u kHz.\n",
                                       cur_freq, cpu_policy->cur);
 
index f8cdde4bf6cd86030a8f829d00fdac862d5847f2..cb2ac01a41a1c55a0faa2480d823aa91b7b3b001 100644 (file)
@@ -65,12 +65,12 @@ static struct notifier_block userspace_cpufreq_notifier_block = {
 
 /**
  * cpufreq_set - set the CPU frequency
+ * @policy: pointer to policy struct where freq is being set
  * @freq: target frequency in kHz
- * @cpu: CPU for which the frequency is to be set
  *
  * Sets the CPU frequency to freq.
  */
-static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
+static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
 {
        int ret = -EINVAL;
 
@@ -102,34 +102,11 @@ static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
 }
 
 
-/************************** sysfs interface ************************/
-static ssize_t show_speed (struct cpufreq_policy *policy, char *buf)
+static ssize_t show_speed(struct cpufreq_policy *policy, char *buf)
 {
-       return sprintf (buf, "%u\n", cpu_cur_freq[policy->cpu]);
+       return sprintf(buf, "%u\n", cpu_cur_freq[policy->cpu]);
 }
 
-static ssize_t
-store_speed (struct cpufreq_policy *policy, const char *buf, size_t count)
-{
-       unsigned int freq = 0;
-       unsigned int ret;
-
-       ret = sscanf (buf, "%u", &freq);
-       if (ret != 1)
-               return -EINVAL;
-
-       cpufreq_set(freq, policy);
-
-       return count;
-}
-
-static struct freq_attr freq_attr_scaling_setspeed =
-{
-       .attr = { .name = "scaling_setspeed", .mode = 0644 },
-       .show = show_speed,
-       .store = store_speed,
-};
-
 static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
                                   unsigned int event)
 {
@@ -142,10 +119,6 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
                        return -EINVAL;
                BUG_ON(!policy->cur);
                mutex_lock(&userspace_mutex);
-               rc = sysfs_create_file (&policy->kobj,
-                                       &freq_attr_scaling_setspeed.attr);
-               if (rc)
-                       goto start_out;
 
                if (cpus_using_userspace_governor == 0) {
                        cpufreq_register_notifier(
@@ -160,7 +133,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
                cpu_cur_freq[cpu] = policy->cur;
                cpu_set_freq[cpu] = policy->cur;
                dprintk("managing cpu %u started (%u - %u kHz, currently %u kHz)\n", cpu, cpu_min_freq[cpu], cpu_max_freq[cpu], cpu_cur_freq[cpu]);
-start_out:
+
                mutex_unlock(&userspace_mutex);
                break;
        case CPUFREQ_GOV_STOP:
@@ -176,7 +149,6 @@ start_out:
                cpu_min_freq[cpu] = 0;
                cpu_max_freq[cpu] = 0;
                cpu_set_freq[cpu] = 0;
-               sysfs_remove_file (&policy->kobj, &freq_attr_scaling_setspeed.attr);
                dprintk("managing cpu %u stopped\n", cpu);
                mutex_unlock(&userspace_mutex);
                break;
@@ -211,6 +183,8 @@ start_out:
 struct cpufreq_governor cpufreq_gov_userspace = {
        .name           = "userspace",
        .governor       = cpufreq_governor_userspace,
+       .store_setspeed = cpufreq_set,
+       .show_setspeed  = show_speed,
        .owner          = THIS_MODULE,
 };
 EXPORT_SYMBOL(cpufreq_gov_userspace);
index 5409f3afb3f85fab2a0b7e160c2972805b0a374d..ae6cd60d5c148979ddf4e911510db24b60e163d5 100644 (file)
@@ -171,7 +171,7 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
 
 static struct cpufreq_frequency_table *show_table[NR_CPUS];
 /**
- * show_scaling_governor - show the current policy for the specified CPU
+ * show_available_freqs - show available frequencies for the specified CPU
  */
 static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
 {
index 3bed4127d4ad364431427b01e323dce256bc4278..7dbc4a83c45c481cdf743fb531c95a4b67a8bb5a 100644 (file)
@@ -1,13 +1,13 @@
 
 config CPU_IDLE
        bool "CPU idle PM support"
+       default ACPI
        help
          CPU idle is a generic framework for supporting software-controlled
          idle processor power management.  It includes modular cross-platform
          governors that can be swapped during runtime.
 
-         If you're using a mobile platform that supports CPU idle PM (e.g.
-         an ACPI-capable notebook), you should say Y here.
+         If you're using an ACPI-enabled platform, you should say Y here.
 
 config CPU_IDLE_GOV_LADDER
        bool
index 2a98d99cbd46075707c15572dff6ace4e6c602c3..2c4b2d47973e195cbb0422a9b539400a2ad5ef5e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/pm_qos_params.h>
 #include <linux/cpu.h>
 #include <linux/cpuidle.h>
+#include <linux/ktime.h>
 
 #include "cpuidle.h"
 
@@ -180,6 +181,44 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
 
 EXPORT_SYMBOL_GPL(cpuidle_disable_device);
 
+#ifdef CONFIG_ARCH_HAS_CPU_RELAX
+static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
+{
+       ktime_t t1, t2;
+       s64 diff;
+       int ret;
+
+       t1 = ktime_get();
+       local_irq_enable();
+       while (!need_resched())
+               cpu_relax();
+
+       t2 = ktime_get();
+       diff = ktime_to_us(ktime_sub(t2, t1));
+       if (diff > INT_MAX)
+               diff = INT_MAX;
+
+       ret = (int) diff;
+       return ret;
+}
+
+static void poll_idle_init(struct cpuidle_device *dev)
+{
+       struct cpuidle_state *state = &dev->states[0];
+
+       cpuidle_set_statedata(state, NULL);
+
+       snprintf(state->name, CPUIDLE_NAME_LEN, "C0 (poll idle)");
+       state->exit_latency = 0;
+       state->target_residency = 0;
+       state->power_usage = -1;
+       state->flags = CPUIDLE_FLAG_POLL | CPUIDLE_FLAG_TIME_VALID;
+       state->enter = poll_idle;
+}
+#else
+static void poll_idle_init(struct cpuidle_device *dev) {}
+#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
+
 /**
  * cpuidle_register_device - registers a CPU's idle PM feature
  * @dev: the cpu
@@ -198,6 +237,8 @@ int cpuidle_register_device(struct cpuidle_device *dev)
 
        mutex_lock(&cpuidle_lock);
 
+       poll_idle_init(dev);
+
        per_cpu(cpuidle_devices, dev->cpu) = dev;
        list_add(&dev->device_list, &cpuidle_detected_devices);
        if ((ret = cpuidle_add_sysfs(sys_dev))) {
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 9008ed5ef4ce2e384b41c591cdc7c629a08af324..e0bade732376555214e04831d7a27b45a3f3ee89 100644 (file)
@@ -489,12 +489,3 @@ int dmi_get_year(int field)
 
        return year;
 }
-
-/**
- *     dmi_get_slot - return dmi_ident[slot]
- *     @slot:  index into dmi_ident[]
- */
-char *dmi_get_slot(int slot)
-{
-       return(dmi_ident[slot]);
-}
index 86c66c345f8b76f8274272796917c740ba312e26..0c94770b7f83cd5fca272ba22877a9f045121904 100644 (file)
@@ -905,7 +905,7 @@ static ssize_t applesmc_key_at_index_store(struct device *dev,
 }
 
 static struct led_classdev applesmc_backlight = {
-       .name                   = "smc:kbd_backlight",
+       .name                   = "smc::kbd_backlight",
        .default_trigger        = "nand-disk",
        .brightness_set         = applesmc_brightness_set,
 };
index b438d998625c695f3d7f031ecf851f8c2683be18..72176f3d49cb3ad5e0c091c35fdcebff9047a984 100644 (file)
@@ -998,12 +998,12 @@ static void wistron_wifi_led_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev wistron_mail_led = {
-       .name                   = "mail:green",
+       .name                   = "wistron:green:mail",
        .brightness_set         = wistron_mail_led_set,
 };
 
 static struct led_classdev wistron_wifi_led = {
-       .name                   = "wifi:red",
+       .name                   = "wistron:red:wifi",
        .brightness_set         = wistron_wifi_led_set,
 };
 
index ec568fa1c6cc3b2ec92e6314de868416bb1e2ded..851a3b01781e71e05a1bb1fa7d5cdc1e05cc7187 100644 (file)
@@ -39,15 +39,6 @@ config LEDS_SPITZ
          This option enables support for the LEDs on Sharp Zaurus
          SL-Cxx00 series (C1000, C3000, C3100).
 
-config LEDS_IXP4XX
-       tristate "LED Support for GPIO connected LEDs on IXP4XX processors"
-       depends on LEDS_CLASS && ARCH_IXP4XX
-       help
-         This option enables support for the LEDs connected to GPIO
-         outputs of the Intel IXP4XX processors.  To be useful the
-         particular board must have LEDs and they must be connected
-         to the GPIO lines.  If unsure, say Y.
-
 config LEDS_TOSA
        tristate "LED Support for the Sharp SL-6000 series"
        depends on LEDS_CLASS && PXA_SHARPSL
@@ -100,6 +91,13 @@ config LEDS_COBALT_RAQ
        help
          This option enables support for the Cobalt Raq series LEDs.
 
+config LEDS_HP6XX
+       tristate "LED Support for the HP Jornada 6xx"
+       depends on LEDS_CLASS && SH_HP6XX
+       help
+         This option enables led support for the handheld
+         HP Jornada 620/660/680/690.
+
 config LEDS_GPIO
        tristate "LED Support for GPIO connected LEDs"
        depends on LEDS_CLASS && GENERIC_GPIO
@@ -114,6 +112,32 @@ config LEDS_CM_X270
        help
          This option enables support for the CM-X270 LEDs.
 
+config LEDS_CLEVO_MAIL
+       tristate "Mail LED on Clevo notebook (EXPERIMENTAL)"
+       depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI && EXPERIMENTAL
+       help
+         This driver makes the mail LED accessible from userspace
+         programs through the leds subsystem. This LED have three
+         known mode: off, blink at 0.5Hz and blink at 1Hz.
+
+         The driver supports two kinds of interface: using ledtrig-timer
+         or through /sys/class/leds/clevo::mail/brightness. As this LED
+         cannot change it's brightness it blinks instead. The brightness
+         value 0 means off, 1..127 means blink at 0.5Hz and 128..255 means
+         blink at 1Hz.
+
+         This module can drive the mail LED for the following notebooks:
+
+               Clevo D410J
+               Clevo D410V
+               Clevo D400V/D470V (not tested, but might work)
+               Clevo M540N
+               Clevo M5x0N (not tested, but might work)
+               Positivo Mobile (Clevo M5x0V)
+
+         To compile this driver as a module, choose M here: the
+         module will be called leds-clevo-mail.
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
@@ -128,7 +152,11 @@ config LEDS_TRIGGER_TIMER
        depends on LEDS_TRIGGERS
        help
          This allows LEDs to be controlled by a programmable timer
-         via sysfs. If unsure, say Y.
+         via sysfs. Some LED hardware can be programmed to start
+         blinking the LED without any further software interaction.
+         For more details read Documentation/leds-class.txt.
+
+         If unsure, say Y.
 
 config LEDS_TRIGGER_IDE_DISK
        bool "LED IDE Disk Trigger"
index a60de1b46c2cd28ec7c3a88471949877f1006aa8..bc6afc8dcb278d8be7e3b71cfe65412649da6c32 100644 (file)
@@ -8,7 +8,6 @@ obj-$(CONFIG_LEDS_TRIGGERS)             += led-triggers.o
 obj-$(CONFIG_LEDS_CORGI)               += leds-corgi.o
 obj-$(CONFIG_LEDS_LOCOMO)              += leds-locomo.o
 obj-$(CONFIG_LEDS_SPITZ)               += leds-spitz.o
-obj-$(CONFIG_LEDS_IXP4XX)              += leds-ixp4xx-gpio.o
 obj-$(CONFIG_LEDS_TOSA)                        += leds-tosa.o
 obj-$(CONFIG_LEDS_S3C24XX)             += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)           += leds-ams-delta.o
@@ -19,6 +18,8 @@ obj-$(CONFIG_LEDS_COBALT_QUBE)                += leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)          += leds-cobalt-raq.o
 obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
 obj-$(CONFIG_LEDS_CM_X270)              += leds-cm-x270.o
+obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
+obj-$(CONFIG_LEDS_HP6XX)               += leds-hp6xx.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)       += ledtrig-timer.o
index 599878c8e7146fb65f2799ca6cfba1a13dc652c0..9e3077463d8481944e351b466e3d4e6749751cb9 100644 (file)
@@ -37,42 +37,42 @@ static void ams_delta_led_set(struct led_classdev *led_cdev,
 static struct ams_delta_led ams_delta_leds[] = {
        {
                .cdev           = {
-                       .name           = "ams-delta:camera",
+                       .name           = "ams-delta::camera",
                        .brightness_set = ams_delta_led_set,
                },
                .bitmask        = AMS_DELTA_LATCH1_LED_CAMERA,
        },
        {
                .cdev           = {
-                       .name           = "ams-delta:advert",
+                       .name           = "ams-delta::advert",
                        .brightness_set = ams_delta_led_set,
                },
                .bitmask        = AMS_DELTA_LATCH1_LED_ADVERT,
        },
        {
                .cdev           = {
-                       .name           = "ams-delta:email",
+                       .name           = "ams-delta::email",
                        .brightness_set = ams_delta_led_set,
                },
                .bitmask        = AMS_DELTA_LATCH1_LED_EMAIL,
        },
        {
                .cdev           = {
-                       .name           = "ams-delta:handsfree",
+                       .name           = "ams-delta::handsfree",
                        .brightness_set = ams_delta_led_set,
                },
                .bitmask        = AMS_DELTA_LATCH1_LED_HANDSFREE,
        },
        {
                .cdev           = {
-                       .name           = "ams-delta:voicemail",
+                       .name           = "ams-delta::voicemail",
                        .brightness_set = ams_delta_led_set,
                },
                .bitmask        = AMS_DELTA_LATCH1_LED_VOICEMAIL,
        },
        {
                .cdev           = {
-                       .name           = "ams-delta:voice",
+                       .name           = "ams-delta::voice",
                        .brightness_set = ams_delta_led_set,
                },
                .bitmask        = AMS_DELTA_LATCH1_LED_VOICE,
diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c
new file mode 100644 (file)
index 0000000..6c3d33b
--- /dev/null
@@ -0,0 +1,219 @@
+
+#include <linux/module.h>
+
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/leds.h>
+
+#include <linux/io.h>
+#include <linux/dmi.h>
+
+#include <linux/i8042.h>
+
+#define CLEVO_MAIL_LED_OFF             0x0084
+#define CLEVO_MAIL_LED_BLINK_1HZ       0x008A
+#define CLEVO_MAIL_LED_BLINK_0_5HZ     0x0083
+
+MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
+MODULE_DESCRIPTION("Clevo mail LED driver");
+MODULE_LICENSE("GPL");
+
+static unsigned int __initdata nodetect;
+module_param_named(nodetect, nodetect, bool, 0);
+MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection");
+
+static struct platform_device *pdev;
+
+static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
+{
+       printk(KERN_INFO KBUILD_MODNAME ": '%s' found\n", id->ident);
+       return 1;
+}
+
+/*
+ * struct mail_led_whitelist - List of known good models
+ *
+ * Contains the known good models this driver is compatible with.
+ * When adding a new model try to be as strict as possible. This
+ * makes it possible to keep the false positives (the model is
+ * detected as working, but in reality it is not) as low as
+ * possible.
+ */
+static struct dmi_system_id __initdata mail_led_whitelist[] = {
+       {
+               .callback = clevo_mail_led_dmi_callback,
+               .ident = "Clevo D410J",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "VIA"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "K8N800"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "VT8204B")
+               }
+       },
+       {
+               .callback = clevo_mail_led_dmi_callback,
+               .ident = "Clevo M5x0N",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "M5x0N")
+               }
+       },
+       {
+               .callback = clevo_mail_led_dmi_callback,
+               .ident = "Positivo Mobile",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "CLEVO Co. "),
+                       DMI_MATCH(DMI_BOARD_NAME, "M5X0V "),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Positivo Mobile"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198")
+               }
+       },
+       {
+               .callback = clevo_mail_led_dmi_callback,
+               .ident = "Clevo D410V",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Clevo, Co."),
+                       DMI_MATCH(DMI_BOARD_NAME, "D400V/D470V"),
+                       DMI_MATCH(DMI_BOARD_VERSION, "SS78B"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Rev. A1")
+               }
+       },
+       { }
+};
+
+static void clevo_mail_led_set(struct led_classdev *led_cdev,
+                               enum led_brightness value)
+{
+       if (value == LED_OFF)
+               i8042_command(NULL, CLEVO_MAIL_LED_OFF);
+       else if (value <= LED_HALF)
+               i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
+       else
+               i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ);
+
+}
+
+static int clevo_mail_led_blink(struct led_classdev *led_cdev,
+                               unsigned long* delay_on,
+                               unsigned long* delay_off)
+{
+       int status = -EINVAL;
+
+       if (*delay_on == 0 /* ms */ && *delay_off == 0 /* ms */) {
+               /* Special case: the leds subsystem requested us to
+                * chose one user friendly blinking of the LED, and
+                * start it. Let's blink the led slowly (0.5Hz).
+                */
+               *delay_on = 1000; /* ms */
+               *delay_off = 1000; /* ms */
+               i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
+               status = 0;
+
+       } else if (*delay_on == 500 /* ms */ && *delay_off == 500 /* ms */) {
+               /* blink the led with 1Hz */
+               i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ);
+               status = 0;
+
+       } else if (*delay_on == 1000 /* ms */ && *delay_off == 1000 /* ms */) {
+               /* blink the led with 0.5Hz */
+               i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
+               status = 0;
+
+       } else {
+               printk(KERN_DEBUG KBUILD_MODNAME
+                      ": clevo_mail_led_blink(..., %lu, %lu),"
+                      " returning -EINVAL (unsupported)\n",
+                      *delay_on, *delay_off);
+       }
+
+       return status;
+}
+
+static struct led_classdev clevo_mail_led = {
+       .name                   = "clevo::mail",
+       .brightness_set         = clevo_mail_led_set,
+       .blink_set              = clevo_mail_led_blink,
+};
+
+static int __init clevo_mail_led_probe(struct platform_device *pdev)
+{
+       return led_classdev_register(&pdev->dev, &clevo_mail_led);
+}
+
+static int clevo_mail_led_remove(struct platform_device *pdev)
+{
+       led_classdev_unregister(&clevo_mail_led);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int clevo_mail_led_suspend(struct platform_device *dev,
+                                 pm_message_t state)
+{
+       led_classdev_suspend(&clevo_mail_led);
+       return 0;
+}
+
+static int clevo_mail_led_resume(struct platform_device *dev)
+{
+       led_classdev_resume(&clevo_mail_led);
+       return 0;
+}
+#else
+#define clevo_mail_led_suspend    NULL
+#define clevo_mail_led_resume     NULL
+#endif
+
+static struct platform_driver clevo_mail_led_driver = {
+       .probe          = clevo_mail_led_probe,
+       .remove         = clevo_mail_led_remove,
+       .suspend        = clevo_mail_led_suspend,
+       .resume         = clevo_mail_led_resume,
+       .driver         = {
+               .name           = KBUILD_MODNAME,
+       },
+};
+
+static int __init clevo_mail_led_init(void)
+{
+       int error = 0;
+       int count = 0;
+
+       /* Check with the help of DMI if we are running on supported hardware */
+       if (!nodetect) {
+               count = dmi_check_system(mail_led_whitelist);
+       } else {
+               count = 1;
+               printk(KERN_ERR KBUILD_MODNAME ": Skipping DMI detection. "
+                      "If the driver works on your hardware please "
+                      "report model and the output of dmidecode in tracker "
+                      "at http://sourceforge.net/projects/clevo-mailled/\n");
+       }
+
+       if (!count)
+               return -ENODEV;
+
+       pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
+       if (!IS_ERR(pdev)) {
+               error = platform_driver_probe(&clevo_mail_led_driver,
+                                             clevo_mail_led_probe);
+               if (error) {
+                       printk(KERN_ERR KBUILD_MODNAME
+                              ": Can't probe platform driver\n");
+                       platform_device_unregister(pdev);
+               }
+       } else
+               error = PTR_ERR(pdev);
+
+       return error;
+}
+
+static void __exit clevo_mail_led_exit(void)
+{
+       platform_device_unregister(pdev);
+       platform_driver_unregister(&clevo_mail_led_driver);
+
+       clevo_mail_led_set(NULL, LED_OFF);
+}
+
+module_init(clevo_mail_led_init);
+module_exit(clevo_mail_led_exit);
index cf1dcd719a282eae18e596e7673807b48ef524c5..e45f6c4b59ba4fd6c57293ba60dd55e49013aada 100644 (file)
@@ -38,13 +38,13 @@ static void corgiled_green_set(struct led_classdev *led_cdev, enum led_brightnes
 }
 
 static struct led_classdev corgi_amber_led = {
-       .name                   = "corgi:amber",
+       .name                   = "corgi:amber:charge",
        .default_trigger        = "sharpsl-charge",
        .brightness_set         = corgiled_amber_set,
 };
 
 static struct led_classdev corgi_green_led = {
-       .name                   = "corgi:green",
+       .name                   = "corgi:green:mail",
        .default_trigger        = "nand-disk",
        .brightness_set         = corgiled_green_set,
 };
index 99bc50059d3531499fa78ca369129a5f7d8c0e39..6c0a9c4761ee13ffd2333db779c7b8f42091ea21 100644 (file)
@@ -85,7 +85,7 @@ static int gpio_led_probe(struct platform_device *pdev)
                led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
                led_dat->active_low = cur_led->active_low;
                led_dat->cdev.brightness_set = gpio_led_set;
-               led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
+               led_dat->cdev.brightness = LED_OFF;
 
                ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
                if (ret < 0)
diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c
new file mode 100644 (file)
index 0000000..82d4ec3
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * LED Triggers Core
+ * For the HP Jornada 620/660/680/690 handhelds
+ *
+ * Copyright 2008 Kristoffer Ericson <kristoffer.ericson@gmail.com>
+ *     this driver is based on leds-spitz.c by Richard Purdie.
+ *
+ * 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/platform_device.h>
+#include <linux/leds.h>
+#include <asm/hd64461.h>
+#include <asm/hp6xx.h>
+
+static void hp6xxled_green_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+       u8 v8;
+
+       v8 = inb(PKDR);
+       if (value)
+               outb(v8 & (~PKDR_LED_GREEN), PKDR);
+       else
+               outb(v8 | PKDR_LED_GREEN, PKDR);
+}
+
+static void hp6xxled_red_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+       u16 v16;
+
+       v16 = inw(HD64461_GPBDR);
+       if (value)
+               outw(v16 & (~HD64461_GPBDR_LED_RED), HD64461_GPBDR);
+       else
+               outw(v16 | HD64461_GPBDR_LED_RED, HD64461_GPBDR);
+}
+
+static struct led_classdev hp6xx_red_led = {
+       .name                   = "hp6xx:red",
+       .default_trigger        = "hp6xx-charge",
+       .brightness_set         = hp6xxled_red_set,
+};
+
+static struct led_classdev hp6xx_green_led = {
+       .name                   = "hp6xx:green",
+       .default_trigger        = "ide-disk",
+       .brightness_set         = hp6xxled_green_set,
+};
+
+#ifdef CONFIG_PM
+static int hp6xxled_suspend(struct platform_device *dev, pm_message_t state)
+{
+       led_classdev_suspend(&hp6xx_red_led);
+       led_classdev_suspend(&hp6xx_green_led);
+       return 0;
+}
+
+static int hp6xxled_resume(struct platform_device *dev)
+{
+       led_classdev_resume(&hp6xx_red_led);
+       led_classdev_resume(&hp6xx_green_led);
+       return 0;
+}
+#endif
+
+static int hp6xxled_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = led_classdev_register(&pdev->dev, &hp6xx_red_led);
+       if (ret < 0)
+               return ret;
+
+       ret = led_classdev_register(&pdev->dev, &hp6xx_green_led);
+       if (ret < 0)
+               led_classdev_unregister(&hp6xx_red_led);
+
+       return ret;
+}
+
+static int hp6xxled_remove(struct platform_device *pdev)
+{
+       led_classdev_unregister(&hp6xx_red_led);
+       led_classdev_unregister(&hp6xx_green_led);
+
+       return 0;
+}
+
+static struct platform_driver hp6xxled_driver = {
+       .probe          = hp6xxled_probe,
+       .remove         = hp6xxled_remove,
+#ifdef CONFIG_PM
+       .suspend        = hp6xxled_suspend,
+       .resume         = hp6xxled_resume,
+#endif
+       .driver         = {
+               .name           = "hp6xx-led",
+       },
+};
+
+static int __init hp6xxled_init(void)
+{
+       return platform_driver_register(&hp6xxled_driver);
+}
+
+static void __exit hp6xxled_exit(void)
+{
+       platform_driver_unregister(&hp6xxled_driver);
+}
+
+module_init(hp6xxled_init);
+module_exit(hp6xxled_exit);
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 6xx LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-ixp4xx-gpio.c b/drivers/leds/leds-ixp4xx-gpio.c
deleted file mode 100644 (file)
index 7dcf0b9..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * IXP4XX GPIO driver LED driver
- *
- * Author: John Bowler <jbowler@acm.org>
- *
- * Copyright (c) 2006 John Bowler
- *
- * Permission is hereby granted, free of charge, to any
- * person obtaining a copy of this software and associated
- * documentation files (the "Software"), to deal in the
- * Software without restriction, including without
- * limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice
- * shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
- * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
- * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/leds.h>
-#include <asm/arch/hardware.h>
-
-extern spinlock_t gpio_lock;
-
-/* Up to 16 gpio lines are possible. */
-#define GPIO_MAX 16
-static struct ixp4xxgpioled_device {
-       struct led_classdev ancestor;
-       int               flags;
-} ixp4xxgpioled_devices[GPIO_MAX];
-
-void ixp4xxgpioled_brightness_set(struct led_classdev *pled,
-                               enum led_brightness value)
-{
-       const struct ixp4xxgpioled_device *const ixp4xx_dev =
-               container_of(pled, struct ixp4xxgpioled_device, ancestor);
-       const u32 gpio_pin = ixp4xx_dev - ixp4xxgpioled_devices;
-
-       if (gpio_pin < GPIO_MAX && ixp4xx_dev->ancestor.name != 0) {
-               /* Set or clear the 'gpio_pin' bit according to the style
-                * and the required setting (value > 0 == on)
-                */
-               const int gpio_value =
-                       (value > 0) == (ixp4xx_dev->flags != IXP4XX_GPIO_LOW) ?
-                               IXP4XX_GPIO_HIGH : IXP4XX_GPIO_LOW;
-
-               {
-                       unsigned long flags;
-                       spin_lock_irqsave(&gpio_lock, flags);
-                       gpio_line_set(gpio_pin, gpio_value);
-                       spin_unlock_irqrestore(&gpio_lock, flags);
-               }
-       }
-}
-
-/* LEDs are described in resources, the following iterates over the valid
- * LED resources.
- */
-#define for_all_leds(i, pdev) \
-       for (i=0; i<pdev->num_resources; ++i) \
-               if (pdev->resource[i].start < GPIO_MAX && \
-                       pdev->resource[i].name != 0)
-
-/* The following applies 'operation' to each LED from the given platform,
- * the function always returns 0 to allow tail call elimination.
- */
-static int apply_to_all_leds(struct platform_device *pdev,
-       void (*operation)(struct led_classdev *pled))
-{
-       int i;
-
-       for_all_leds(i, pdev)
-               operation(&ixp4xxgpioled_devices[pdev->resource[i].start].ancestor);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int ixp4xxgpioled_suspend(struct platform_device *pdev,
-                               pm_message_t state)
-{
-       return apply_to_all_leds(pdev, led_classdev_suspend);
-}
-
-static int ixp4xxgpioled_resume(struct platform_device *pdev)
-{
-       return apply_to_all_leds(pdev, led_classdev_resume);
-}
-#endif
-
-static void ixp4xxgpioled_remove_one_led(struct led_classdev *pled)
-{
-       led_classdev_unregister(pled);
-       pled->name = 0;
-}
-
-static int ixp4xxgpioled_remove(struct platform_device *pdev)
-{
-       return apply_to_all_leds(pdev, ixp4xxgpioled_remove_one_led);
-}
-
-static int ixp4xxgpioled_probe(struct platform_device *pdev)
-{
-       /* The board level has to tell the driver where the
-        * LEDs are connected - there is no way to find out
-        * electrically.  It must also say whether the GPIO
-        * lines are active high or active low.
-        *
-        * To do this read the num_resources (the number of
-        * LEDs) and the struct resource (the data for each
-        * LED).  The name comes from the resource, and it
-        * isn't copied.
-        */
-       int i;
-
-       for_all_leds(i, pdev) {
-               const u8 gpio_pin = pdev->resource[i].start;
-               int      rc;
-
-               if (ixp4xxgpioled_devices[gpio_pin].ancestor.name == 0) {
-                       unsigned long flags;
-
-                       spin_lock_irqsave(&gpio_lock, flags);
-                       gpio_line_config(gpio_pin, IXP4XX_GPIO_OUT);
-                       /* The config can, apparently, reset the state,
-                        * I suspect the gpio line may be an input and
-                        * the config may cause the line to be latched,
-                        * so the setting depends on how the LED is
-                        * connected to the line (which affects how it
-                        * floats if not driven).
-                        */
-                       gpio_line_set(gpio_pin, IXP4XX_GPIO_HIGH);
-                       spin_unlock_irqrestore(&gpio_lock, flags);
-
-                       ixp4xxgpioled_devices[gpio_pin].flags =
-                               pdev->resource[i].flags & IORESOURCE_BITS;
-
-                       ixp4xxgpioled_devices[gpio_pin].ancestor.name =
-                               pdev->resource[i].name;
-
-                       /* This is how a board manufacturer makes the LED
-                        * come on on reset - the GPIO line will be high, so
-                        * make the LED light when the line is low...
-                        */
-                       if (ixp4xxgpioled_devices[gpio_pin].flags != IXP4XX_GPIO_LOW)
-                               ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 100;
-                       else
-                               ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 0;
-
-                       ixp4xxgpioled_devices[gpio_pin].ancestor.flags = 0;
-
-                       ixp4xxgpioled_devices[gpio_pin].ancestor.brightness_set =
-                               ixp4xxgpioled_brightness_set;
-
-                       ixp4xxgpioled_devices[gpio_pin].ancestor.default_trigger = 0;
-               }
-
-               rc = led_classdev_register(&pdev->dev,
-                               &ixp4xxgpioled_devices[gpio_pin].ancestor);
-               if (rc < 0) {
-                       ixp4xxgpioled_devices[gpio_pin].ancestor.name = 0;
-                       ixp4xxgpioled_remove(pdev);
-                       return rc;
-               }
-       }
-
-       return 0;
-}
-
-static struct platform_driver ixp4xxgpioled_driver = {
-       .probe   = ixp4xxgpioled_probe,
-       .remove  = ixp4xxgpioled_remove,
-#ifdef CONFIG_PM
-       .suspend = ixp4xxgpioled_suspend,
-       .resume  = ixp4xxgpioled_resume,
-#endif
-       .driver  = {
-               .name = "IXP4XX-GPIO-LED",
-       },
-};
-
-static int __init ixp4xxgpioled_init(void)
-{
-       return platform_driver_register(&ixp4xxgpioled_driver);
-}
-
-static void __exit ixp4xxgpioled_exit(void)
-{
-       platform_driver_unregister(&ixp4xxgpioled_driver);
-}
-
-module_init(ixp4xxgpioled_init);
-module_exit(ixp4xxgpioled_exit);
-
-MODULE_AUTHOR("John Bowler <jbowler@acm.org>");
-MODULE_DESCRIPTION("IXP4XX GPIO LED driver");
-MODULE_LICENSE("Dual MIT/GPL");
index 2207335e9212e97b64a05bdd290819ceee83a89d..7295f7f52185162d68b98f72dc5dc66ee565c9a0 100644 (file)
@@ -43,13 +43,13 @@ static void locomoled_brightness_set1(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev locomo_led0 = {
-       .name                   = "locomo:amber",
+       .name                   = "locomo:amber:charge",
        .default_trigger        = "sharpsl-charge",
        .brightness_set         = locomoled_brightness_set0,
 };
 
 static struct led_classdev locomo_led1 = {
-       .name                   = "locomo:green",
+       .name                   = "locomo:green:mail",
        .default_trigger        = "nand-disk",
        .brightness_set         = locomoled_brightness_set1,
 };
index 45ba3d45bcb8a8387461883ae050aa308213a812..054360473c9490ea6e4251188dcbf4cad92fa310 100644 (file)
@@ -31,7 +31,7 @@ static void net48xx_error_led_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev net48xx_error_led = {
-       .name           = "net48xx:error",
+       .name           = "net48xx::error",
        .brightness_set = net48xx_error_led_set,
 };
 
index 126d09cc96ecf97cad158fe47315e73c13e96779..93e1012b17e620c1c85e8ad037180142676d11b4 100644 (file)
@@ -38,13 +38,13 @@ static void spitzled_green_set(struct led_classdev *led_cdev, enum led_brightnes
 }
 
 static struct led_classdev spitz_amber_led = {
-       .name                   = "spitz:amber",
+       .name                   = "spitz:amber:charge",
        .default_trigger        = "sharpsl-charge",
        .brightness_set         = spitzled_amber_set,
 };
 
 static struct led_classdev spitz_green_led = {
-       .name                   = "spitz:green",
+       .name                   = "spitz:green:hddactivity",
        .default_trigger        = "ide-disk",
        .brightness_set         = spitzled_green_set,
 };
@@ -72,8 +72,10 @@ static int spitzled_probe(struct platform_device *pdev)
 {
        int ret;
 
-       if (machine_is_akita())
+       if (machine_is_akita()) {
+               spitz_green_led.name = "spitz:green:mail";
                spitz_green_led.default_trigger = "nand-disk";
+       }
 
        ret = led_classdev_register(&pdev->dev, &spitz_amber_led);
        if (ret < 0)
index fb2416a38303ce87aab0766dac1c9997ecca506a..9e0a188fbb0a224ceb66fc7fe3b22a0bc4668437 100644 (file)
@@ -45,13 +45,13 @@ static void tosaled_green_set(struct led_classdev *led_cdev,
 }
 
 static struct led_classdev tosa_amber_led = {
-       .name                   = "tosa:amber",
+       .name                   = "tosa:amber:charge",
        .default_trigger        = "sharpsl-charge",
        .brightness_set         = tosaled_amber_set,
 };
 
 static struct led_classdev tosa_green_led = {
-       .name                   = "tosa:green",
+       .name                   = "tosa:green:mail",
        .default_trigger        = "nand-disk",
        .brightness_set         = tosaled_green_set,
 };
index 27fb2d8e991fd55343f51021df26887ddffa3f29..7ac61a7b56ad9b5d62a035f05f530a567c5deacb 100644 (file)
 #include <linux/scx200_gpio.h>
 
 #define DRVNAME "wrap-led"
+#define WRAP_POWER_LED_GPIO    2
 #define WRAP_ERROR_LED_GPIO    3
-#define        WRAP_EXTRA_LED_GPIO     18
+#define WRAP_EXTRA_LED_GPIO    18
 
 static struct platform_device *pdev;
 
+static void wrap_power_led_set(struct led_classdev *led_cdev,
+               enum led_brightness value)
+{
+       if (value)
+               scx200_gpio_set_low(WRAP_POWER_LED_GPIO);
+       else
+               scx200_gpio_set_high(WRAP_POWER_LED_GPIO);
+}
+
 static void wrap_error_led_set(struct led_classdev *led_cdev,
                enum led_brightness value)
 {
@@ -42,13 +52,18 @@ static void wrap_extra_led_set(struct led_classdev *led_cdev,
                scx200_gpio_set_high(WRAP_EXTRA_LED_GPIO);
 }
 
+static struct led_classdev wrap_power_led = {
+       .name           = "wrap::power",
+       .brightness_set = wrap_power_led_set,
+};
+
 static struct led_classdev wrap_error_led = {
-       .name           = "wrap:error",
+       .name           = "wrap::error",
        .brightness_set = wrap_error_led_set,
 };
 
 static struct led_classdev wrap_extra_led = {
-       .name           = "wrap:extra",
+       .name           = "wrap::extra",
        .brightness_set = wrap_extra_led_set,
 };
 
@@ -56,6 +71,7 @@ static struct led_classdev wrap_extra_led = {
 static int wrap_led_suspend(struct platform_device *dev,
                pm_message_t state)
 {
+       led_classdev_suspend(&wrap_power_led);
        led_classdev_suspend(&wrap_error_led);
        led_classdev_suspend(&wrap_extra_led);
        return 0;
@@ -63,6 +79,7 @@ static int wrap_led_suspend(struct platform_device *dev,
 
 static int wrap_led_resume(struct platform_device *dev)
 {
+       led_classdev_resume(&wrap_power_led);
        led_classdev_resume(&wrap_error_led);
        led_classdev_resume(&wrap_extra_led);
        return 0;
@@ -76,17 +93,31 @@ static int wrap_led_probe(struct platform_device *pdev)
 {
        int ret;
 
+       ret = led_classdev_register(&pdev->dev, &wrap_power_led);
+       if (ret < 0)
+               return ret;
+
        ret = led_classdev_register(&pdev->dev, &wrap_error_led);
-       if (ret == 0) {
-               ret = led_classdev_register(&pdev->dev, &wrap_extra_led);
-               if (ret < 0)
-                       led_classdev_unregister(&wrap_error_led);
-       }
+       if (ret < 0)
+               goto err1;
+
+       ret = led_classdev_register(&pdev->dev, &wrap_extra_led);
+       if (ret < 0)
+               goto err2;
+
+       return ret;
+
+err2:
+       led_classdev_unregister(&wrap_error_led);
+err1:
+       led_classdev_unregister(&wrap_power_led);
+
        return ret;
 }
 
 static int wrap_led_remove(struct platform_device *pdev)
 {
+       led_classdev_unregister(&wrap_power_led);
        led_classdev_unregister(&wrap_error_led);
        led_classdev_unregister(&wrap_extra_led);
        return 0;
index ed9ff02c77ea742c23c616a0f340c400770c33ec..82c55d6e49023ff9fe2866a819a1c5ec7bad7949 100644 (file)
@@ -77,8 +77,21 @@ static ssize_t led_delay_on_store(struct device *dev,
                count++;
 
        if (count == size) {
-               timer_data->delay_on = state;
-               mod_timer(&timer_data->timer, jiffies + 1);
+               if (timer_data->delay_on != state) {
+                       /* the new value differs from the previous */
+                       timer_data->delay_on = state;
+
+                       /* deactivate previous settings */
+                       del_timer_sync(&timer_data->timer);
+
+                       /* try to activate hardware acceleration, if any */
+                       if (!led_cdev->blink_set ||
+                           led_cdev->blink_set(led_cdev,
+                               &timer_data->delay_on, &timer_data->delay_off)) {
+                               /* no hardware acceleration, blink via timer */
+                               mod_timer(&timer_data->timer, jiffies + 1);
+                       }
+               }
                ret = count;
        }
 
@@ -110,8 +123,21 @@ static ssize_t led_delay_off_store(struct device *dev,
                count++;
 
        if (count == size) {
-               timer_data->delay_off = state;
-               mod_timer(&timer_data->timer, jiffies + 1);
+               if (timer_data->delay_off != state) {
+                       /* the new value differs from the previous */
+                       timer_data->delay_off = state;
+
+                       /* deactivate previous settings */
+                       del_timer_sync(&timer_data->timer);
+
+                       /* try to activate hardware acceleration, if any */
+                       if (!led_cdev->blink_set ||
+                           led_cdev->blink_set(led_cdev,
+                               &timer_data->delay_on, &timer_data->delay_off)) {
+                               /* no hardware acceleration, blink via timer */
+                               mod_timer(&timer_data->timer, jiffies + 1);
+                       }
+               }
                ret = count;
        }
 
@@ -143,6 +169,13 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
        if (rc)
                goto err_out_delayon;
 
+       /* If there is hardware support for blinking, start one
+        * user friendly blink rate chosen by the driver.
+        */
+       if (led_cdev->blink_set)
+               led_cdev->blink_set(led_cdev,
+                       &timer_data->delay_on, &timer_data->delay_off);
+
        return;
 
 err_out_delayon:
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 b5e67c0ff43304d3e16be35525a47e9fc96aaaaf..78cd33861766ed1d8ae6b325cc579e6dbe32f803 100644 (file)
@@ -92,6 +92,22 @@ config TIFM_7XX1
           To compile this driver as a module, choose M here: the module will
          be called tifm_7xx1.
 
+config ACER_WMI
+        tristate "Acer WMI Laptop Extras (EXPERIMENTAL)"
+       depends on X86
+       depends on EXPERIMENTAL
+       depends on ACPI
+       depends on ACPI_WMI
+       depends on LEDS_CLASS
+       depends on BACKLIGHT_CLASS_DEVICE
+       ---help---
+         This is a driver for newer Acer (and Wistron) laptops. It adds
+         wireless radio and bluetooth control, and on some laptops,
+         exposes the mail LED and LCD backlight.
+
+         If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
+         here.
+
 config ASUS_LAPTOP
         tristate "Asus Laptop Extras (EXPERIMENTAL)"
         depends on X86
@@ -126,6 +142,15 @@ config FUJITSU_LAPTOP
 
          If you have a Fujitsu laptop, say Y or M here.
 
+config TC1100_WMI
+       tristate "HP Compaq TC1100 Tablet WMI Extras"
+       depends on X86 && !X86_64
+       depends on ACPI
+       depends on ACPI_WMI
+       ---help---
+         This is a driver for the WMI extensions (wireless and bluetooth power
+         control) of the HP Compaq TC1100 tablet.
+
 config MSI_LAPTOP
         tristate "MSI Laptop Extras"
         depends on X86
@@ -219,6 +244,25 @@ config THINKPAD_ACPI_BAY
 
          If you are not sure, say Y here.
 
+config THINKPAD_ACPI_HOTKEY_POLL
+       bool "Suport NVRAM polling for hot keys"
+       depends on THINKPAD_ACPI
+       default y
+       ---help---
+         Some thinkpad models benefit from NVRAM polling to detect a few of
+         the hot key press events.  If you know your ThinkPad model does not
+         need to do NVRAM polling to support any of the hot keys you use,
+         unselecting this option will save about 1kB of memory.
+
+         ThinkPads T40 and newer, R52 and newer, and X31 and newer are
+         unlikely to need NVRAM polling in their latest BIOS versions.
+
+         NVRAM polling can detect at most the following keys: ThinkPad/Access
+         IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute,
+         Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12).
+
+         If you are not sure, say Y here.  The driver enables polling only if
+         it is strictly necessary to do so.
 
 config ATMEL_SSC
        tristate "Device driver for Atmel SSC peripheral"
@@ -232,4 +276,13 @@ config ATMEL_SSC
 
          If unsure, say N.
 
+config INTEL_MENLOW
+       tristate "Thermal Management driver for Intel menlow platform"
+       depends on ACPI_THERMAL
+       ---help---
+         ACPI thermal management enhancement driver on
+         Intel Menlow platform.
+
+         If unsure, say N.
+
 endif # MISC_DEVICES
index 87f2685d728fed038472818507a48741f873e177..1f41654aae4dae7ad85796fc43bfdf01eecafc31 100644 (file)
@@ -6,8 +6,10 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
 obj-$(CONFIG_IBM_ASM)          += ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)    += hdpuftrs/
 obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
+obj-$(CONFIG_ACER_WMI)     += acer-wmi.o
 obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
 obj-$(CONFIG_ATMEL_SSC)                += atmel-ssc.o
+obj-$(CONFIG_TC1100_WMI)       += tc1100-wmi.o
 obj-$(CONFIG_LKDTM)            += lkdtm.o
 obj-$(CONFIG_TIFM_CORE)        += tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)        += tifm_7xx1.o
@@ -17,3 +19,4 @@ obj-$(CONFIG_SONY_LAPTOP)     += sony-laptop.o
 obj-$(CONFIG_THINKPAD_ACPI)    += thinkpad_acpi.o
 obj-$(CONFIG_FUJITSU_LAPTOP)   += fujitsu-laptop.o
 obj-$(CONFIG_EEPROM_93CX6)     += eeprom_93cx6.o
+obj-$(CONFIG_INTEL_MENLOW)     += intel_menlow.o
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
new file mode 100644 (file)
index 0000000..a4d6775
--- /dev/null
@@ -0,0 +1,1109 @@
+/*
+ *  Acer WMI Laptop Extras
+ *
+ *  Copyright (C) 2007-2008    Carlos Corbacho <carlos@strangeworlds.co.uk>
+ *
+ *  Based on acer_acpi:
+ *    Copyright (C) 2005-2007  E.M. Smith
+ *    Copyright (C) 2007-2008  Carlos Corbacho <cathectic@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define ACER_WMI_VERSION       "0.1"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/dmi.h>
+#include <linux/backlight.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/i8042.h>
+
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Carlos Corbacho");
+MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
+MODULE_LICENSE("GPL");
+
+#define ACER_LOGPREFIX "acer-wmi: "
+#define ACER_ERR KERN_ERR ACER_LOGPREFIX
+#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
+#define ACER_INFO KERN_INFO ACER_LOGPREFIX
+
+/*
+ * The following defines quirks to get some specific functions to work
+ * which are known to not be supported over ACPI-WMI (such as the mail LED
+ * on WMID based Acer's)
+ */
+struct acer_quirks {
+       const char *vendor;
+       const char *model;
+       u16 quirks;
+};
+
+/*
+ * Magic Number
+ * Meaning is unknown - this number is required for writing to ACPI for AMW0
+ * (it's also used in acerhk when directly accessing the BIOS)
+ */
+#define ACER_AMW0_WRITE        0x9610
+
+/*
+ * Bit masks for the AMW0 interface
+ */
+#define ACER_AMW0_WIRELESS_MASK  0x35
+#define ACER_AMW0_BLUETOOTH_MASK 0x34
+#define ACER_AMW0_MAILLED_MASK   0x31
+
+/*
+ * Method IDs for WMID interface
+ */
+#define ACER_WMID_GET_WIRELESS_METHODID                1
+#define ACER_WMID_GET_BLUETOOTH_METHODID       2
+#define ACER_WMID_GET_BRIGHTNESS_METHODID      3
+#define ACER_WMID_SET_WIRELESS_METHODID                4
+#define ACER_WMID_SET_BLUETOOTH_METHODID       5
+#define ACER_WMID_SET_BRIGHTNESS_METHODID      6
+#define ACER_WMID_GET_THREEG_METHODID          10
+#define ACER_WMID_SET_THREEG_METHODID          11
+
+/*
+ * Acer ACPI method GUIDs
+ */
+#define AMW0_GUID1             "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
+#define WMID_GUID1             "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
+#define WMID_GUID2             "95764E09-FB56-4e83-B31A-37761F60994A"
+
+MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
+MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
+
+/* Temporary workaround until the WMI sysfs interface goes in */
+MODULE_ALIAS("dmi:*:*Acer*:*:");
+
+/*
+ * Interface capability flags
+ */
+#define ACER_CAP_MAILLED               (1<<0)
+#define ACER_CAP_WIRELESS              (1<<1)
+#define ACER_CAP_BLUETOOTH             (1<<2)
+#define ACER_CAP_BRIGHTNESS            (1<<3)
+#define ACER_CAP_THREEG                        (1<<4)
+#define ACER_CAP_ANY                   (0xFFFFFFFF)
+
+/*
+ * Interface type flags
+ */
+enum interface_flags {
+       ACER_AMW0,
+       ACER_AMW0_V2,
+       ACER_WMID,
+};
+
+#define ACER_DEFAULT_WIRELESS  0
+#define ACER_DEFAULT_BLUETOOTH 0
+#define ACER_DEFAULT_MAILLED   0
+#define ACER_DEFAULT_THREEG    0
+
+static int max_brightness = 0xF;
+
+static int wireless = -1;
+static int bluetooth = -1;
+static int mailled = -1;
+static int brightness = -1;
+static int threeg = -1;
+static int force_series;
+
+module_param(mailled, int, 0444);
+module_param(wireless, int, 0444);
+module_param(bluetooth, int, 0444);
+module_param(brightness, int, 0444);
+module_param(threeg, int, 0444);
+module_param(force_series, int, 0444);
+MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
+MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
+MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
+MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
+MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
+MODULE_PARM_DESC(force_series, "Force a different laptop series");
+
+struct acer_data {
+       int mailled;
+       int wireless;
+       int bluetooth;
+       int threeg;
+       int brightness;
+};
+
+/* Each low-level interface must define at least some of the following */
+struct wmi_interface {
+       /* The WMI device type */
+       u32 type;
+
+       /* The capabilities this interface provides */
+       u32 capability;
+
+       /* Private data for the current interface */
+       struct acer_data data;
+};
+
+/* The static interface pointer, points to the currently detected interface */
+static struct wmi_interface *interface;
+
+/*
+ * Embedded Controller quirks
+ * Some laptops require us to directly access the EC to either enable or query
+ * features that are not available through WMI.
+ */
+
+struct quirk_entry {
+       u8 wireless;
+       u8 mailled;
+       u8 brightness;
+       u8 bluetooth;
+};
+
+static struct quirk_entry *quirks;
+
+static void set_quirks(void)
+{
+       if (quirks->mailled)
+               interface->capability |= ACER_CAP_MAILLED;
+
+       if (quirks->brightness)
+               interface->capability |= ACER_CAP_BRIGHTNESS;
+}
+
+static int dmi_matched(const struct dmi_system_id *dmi)
+{
+       quirks = dmi->driver_data;
+       return 0;
+}
+
+static struct quirk_entry quirk_unknown = {
+};
+
+static struct quirk_entry quirk_acer_travelmate_2490 = {
+       .mailled = 1,
+};
+
+/* This AMW0 laptop has no bluetooth */
+static struct quirk_entry quirk_medion_md_98300 = {
+       .wireless = 1,
+};
+
+static struct dmi_system_id acer_quirks[] = {
+       {
+               .callback = dmi_matched,
+               .ident = "Acer Aspire 3100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
+               },
+               .driver_data = &quirk_acer_travelmate_2490,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Acer Aspire 5100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
+               },
+               .driver_data = &quirk_acer_travelmate_2490,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Acer Aspire 5630",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
+               },
+               .driver_data = &quirk_acer_travelmate_2490,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Acer Aspire 5650",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
+               },
+               .driver_data = &quirk_acer_travelmate_2490,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Acer Aspire 5680",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
+               },
+               .driver_data = &quirk_acer_travelmate_2490,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Acer Aspire 9110",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
+               },
+               .driver_data = &quirk_acer_travelmate_2490,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Acer TravelMate 2490",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
+               },
+               .driver_data = &quirk_acer_travelmate_2490,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Medion MD 98300",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
+               },
+               .driver_data = &quirk_medion_md_98300,
+       },
+       {}
+};
+
+/* Find which quirks are needed for a particular vendor/ model pair */
+static void find_quirks(void)
+{
+       if (!force_series) {
+               dmi_check_system(acer_quirks);
+       } else if (force_series == 2490) {
+               quirks = &quirk_acer_travelmate_2490;
+       }
+
+       if (quirks == NULL)
+               quirks = &quirk_unknown;
+
+       set_quirks();
+}
+
+/*
+ * General interface convenience methods
+ */
+
+static bool has_cap(u32 cap)
+{
+       if ((interface->capability & cap) != 0)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * AMW0 (V1) interface
+ */
+struct wmab_args {
+       u32 eax;
+       u32 ebx;
+       u32 ecx;
+       u32 edx;
+};
+
+struct wmab_ret {
+       u32 eax;
+       u32 ebx;
+       u32 ecx;
+       u32 edx;
+       u32 eex;
+};
+
+static acpi_status wmab_execute(struct wmab_args *regbuf,
+struct acpi_buffer *result)
+{
+       struct acpi_buffer input;
+       acpi_status status;
+       input.length = sizeof(struct wmab_args);
+       input.pointer = (u8 *)regbuf;
+
+       status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
+
+       return status;
+}
+
+static acpi_status AMW0_get_u32(u32 *value, u32 cap,
+struct wmi_interface *iface)
+{
+       int err;
+       u8 result;
+
+       switch (cap) {
+       case ACER_CAP_MAILLED:
+               switch (quirks->mailled) {
+               default:
+                       err = ec_read(0xA, &result);
+                       if (err)
+                               return AE_ERROR;
+                       *value = (result >> 7) & 0x1;
+                       return AE_OK;
+               }
+               break;
+       case ACER_CAP_WIRELESS:
+               switch (quirks->wireless) {
+               case 1:
+                       err = ec_read(0x7B, &result);
+                       if (err)
+                               return AE_ERROR;
+                       *value = result & 0x1;
+                       return AE_OK;
+               default:
+                       err = ec_read(0xA, &result);
+                       if (err)
+                               return AE_ERROR;
+                       *value = (result >> 2) & 0x1;
+                       return AE_OK;
+               }
+               break;
+       case ACER_CAP_BLUETOOTH:
+               switch (quirks->bluetooth) {
+               default:
+                       err = ec_read(0xA, &result);
+                       if (err)
+                               return AE_ERROR;
+                       *value = (result >> 4) & 0x1;
+                       return AE_OK;
+               }
+               break;
+       case ACER_CAP_BRIGHTNESS:
+               switch (quirks->brightness) {
+               default:
+                       err = ec_read(0x83, &result);
+                       if (err)
+                               return AE_ERROR;
+                       *value = result;
+                       return AE_OK;
+               }
+               break;
+       default:
+               return AE_BAD_ADDRESS;
+       }
+       return AE_OK;
+}
+
+static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+{
+       struct wmab_args args;
+
+       args.eax = ACER_AMW0_WRITE;
+       args.ebx = value ? (1<<8) : 0;
+       args.ecx = args.edx = 0;
+
+       switch (cap) {
+       case ACER_CAP_MAILLED:
+               if (value > 1)
+                       return AE_BAD_PARAMETER;
+               args.ebx |= ACER_AMW0_MAILLED_MASK;
+               break;
+       case ACER_CAP_WIRELESS:
+               if (value > 1)
+                       return AE_BAD_PARAMETER;
+               args.ebx |= ACER_AMW0_WIRELESS_MASK;
+               break;
+       case ACER_CAP_BLUETOOTH:
+               if (value > 1)
+                       return AE_BAD_PARAMETER;
+               args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
+               break;
+       case ACER_CAP_BRIGHTNESS:
+               if (value > max_brightness)
+                       return AE_BAD_PARAMETER;
+               switch (quirks->brightness) {
+               case 1:
+                       return ec_write(0x83, value);
+               default:
+                       return AE_BAD_ADDRESS;
+               break;
+               }
+       default:
+               return AE_BAD_ADDRESS;
+       }
+
+       /* Actually do the set */
+       return wmab_execute(&args, NULL);
+}
+
+static acpi_status AMW0_find_mailled(void)
+{
+       struct wmab_args args;
+       struct wmab_ret ret;
+       acpi_status status = AE_OK;
+       struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+
+       args.eax = 0x86;
+       args.ebx = args.ecx = args.edx = 0;
+
+       status = wmab_execute(&args, &out);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = (union acpi_object *) out.pointer;
+       if (obj && obj->type == ACPI_TYPE_BUFFER &&
+       obj->buffer.length == sizeof(struct wmab_ret)) {
+               ret = *((struct wmab_ret *) obj->buffer.pointer);
+       } else {
+               return AE_ERROR;
+       }
+
+       if (ret.eex & 0x1)
+               interface->capability |= ACER_CAP_MAILLED;
+
+       kfree(out.pointer);
+
+       return AE_OK;
+}
+
+static acpi_status AMW0_set_capabilities(void)
+{
+       struct wmab_args args;
+       struct wmab_ret ret;
+       acpi_status status = AE_OK;
+       struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+
+       args.eax = ACER_AMW0_WRITE;
+       args.ecx = args.edx = 0;
+
+       args.ebx = 0xa2 << 8;
+       args.ebx |= ACER_AMW0_WIRELESS_MASK;
+
+       status = wmab_execute(&args, &out);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = (union acpi_object *) out.pointer;
+       if (obj && obj->type == ACPI_TYPE_BUFFER &&
+       obj->buffer.length == sizeof(struct wmab_ret)) {
+               ret = *((struct wmab_ret *) obj->buffer.pointer);
+       } else {
+               return AE_ERROR;
+       }
+
+       if (ret.eax & 0x1)
+               interface->capability |= ACER_CAP_WIRELESS;
+
+       args.ebx = 2 << 8;
+       args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
+
+       status = wmab_execute(&args, &out);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = (union acpi_object *) out.pointer;
+       if (obj && obj->type == ACPI_TYPE_BUFFER
+       && obj->buffer.length == sizeof(struct wmab_ret)) {
+               ret = *((struct wmab_ret *) obj->buffer.pointer);
+       } else {
+               return AE_ERROR;
+       }
+
+       if (ret.eax & 0x1)
+               interface->capability |= ACER_CAP_BLUETOOTH;
+
+       kfree(out.pointer);
+
+       /*
+        * This appears to be safe to enable, since all Wistron based laptops
+        * appear to use the same EC register for brightness, even if they
+        * differ for wireless, etc
+        */
+       interface->capability |= ACER_CAP_BRIGHTNESS;
+
+       return AE_OK;
+}
+
+static struct wmi_interface AMW0_interface = {
+       .type = ACER_AMW0,
+};
+
+static struct wmi_interface AMW0_V2_interface = {
+       .type = ACER_AMW0_V2,
+};
+
+/*
+ * New interface (The WMID interface)
+ */
+static acpi_status
+WMI_execute_u32(u32 method_id, u32 in, u32 *out)
+{
+       struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
+       struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       u32 tmp;
+       acpi_status status;
+
+       status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = (union acpi_object *) result.pointer;
+       if (obj && obj->type == ACPI_TYPE_BUFFER &&
+               obj->buffer.length == sizeof(u32)) {
+               tmp = *((u32 *) obj->buffer.pointer);
+       } else {
+               tmp = 0;
+       }
+
+       if (out)
+               *out = tmp;
+
+       kfree(result.pointer);
+
+       return status;
+}
+
+static acpi_status WMID_get_u32(u32 *value, u32 cap,
+struct wmi_interface *iface)
+{
+       acpi_status status;
+       u8 tmp;
+       u32 result, method_id = 0;
+
+       switch (cap) {
+       case ACER_CAP_WIRELESS:
+               method_id = ACER_WMID_GET_WIRELESS_METHODID;
+               break;
+       case ACER_CAP_BLUETOOTH:
+               method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
+               break;
+       case ACER_CAP_BRIGHTNESS:
+               method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
+               break;
+       case ACER_CAP_THREEG:
+               method_id = ACER_WMID_GET_THREEG_METHODID;
+               break;
+       case ACER_CAP_MAILLED:
+               if (quirks->mailled == 1) {
+                       ec_read(0x9f, &tmp);
+                       *value = tmp & 0x1;
+                       return 0;
+               }
+       default:
+               return AE_BAD_ADDRESS;
+       }
+       status = WMI_execute_u32(method_id, 0, &result);
+
+       if (ACPI_SUCCESS(status))
+               *value = (u8)result;
+
+       return status;
+}
+
+static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+{
+       u32 method_id = 0;
+       char param;
+
+       switch (cap) {
+       case ACER_CAP_BRIGHTNESS:
+               if (value > max_brightness)
+                       return AE_BAD_PARAMETER;
+               method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
+               break;
+       case ACER_CAP_WIRELESS:
+               if (value > 1)
+                       return AE_BAD_PARAMETER;
+               method_id = ACER_WMID_SET_WIRELESS_METHODID;
+               break;
+       case ACER_CAP_BLUETOOTH:
+               if (value > 1)
+                       return AE_BAD_PARAMETER;
+               method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
+               break;
+       case ACER_CAP_THREEG:
+               if (value > 1)
+                       return AE_BAD_PARAMETER;
+               method_id = ACER_WMID_SET_THREEG_METHODID;
+               break;
+       case ACER_CAP_MAILLED:
+               if (value > 1)
+                       return AE_BAD_PARAMETER;
+               if (quirks->mailled == 1) {
+                       param = value ? 0x92 : 0x93;
+                       i8042_command(&param, 0x1059);
+                       return 0;
+               }
+               break;
+       default:
+               return AE_BAD_ADDRESS;
+       }
+       return WMI_execute_u32(method_id, (u32)value, NULL);
+}
+
+static acpi_status WMID_set_capabilities(void)
+{
+       struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object *obj;
+       acpi_status status;
+       u32 devices;
+
+       status = wmi_query_block(WMID_GUID2, 1, &out);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = (union acpi_object *) out.pointer;
+       if (obj && obj->type == ACPI_TYPE_BUFFER &&
+               obj->buffer.length == sizeof(u32)) {
+               devices = *((u32 *) obj->buffer.pointer);
+       } else {
+               return AE_ERROR;
+       }
+
+       /* Not sure on the meaning of the relevant bits yet to detect these */
+       interface->capability |= ACER_CAP_WIRELESS;
+       interface->capability |= ACER_CAP_THREEG;
+
+       /* WMID always provides brightness methods */
+       interface->capability |= ACER_CAP_BRIGHTNESS;
+
+       if (devices & 0x10)
+               interface->capability |= ACER_CAP_BLUETOOTH;
+
+       if (!(devices & 0x20))
+               max_brightness = 0x9;
+
+       return status;
+}
+
+static struct wmi_interface wmid_interface = {
+       .type = ACER_WMID,
+};
+
+/*
+ * Generic Device (interface-independent)
+ */
+
+static acpi_status get_u32(u32 *value, u32 cap)
+{
+       acpi_status status = AE_BAD_ADDRESS;
+
+       switch (interface->type) {
+       case ACER_AMW0:
+               status = AMW0_get_u32(value, cap, interface);
+               break;
+       case ACER_AMW0_V2:
+               if (cap == ACER_CAP_MAILLED) {
+                       status = AMW0_get_u32(value, cap, interface);
+                       break;
+               }
+       case ACER_WMID:
+               status = WMID_get_u32(value, cap, interface);
+               break;
+       }
+
+       return status;
+}
+
+static acpi_status set_u32(u32 value, u32 cap)
+{
+       if (interface->capability & cap) {
+               switch (interface->type) {
+               case ACER_AMW0:
+                       return AMW0_set_u32(value, cap, interface);
+               case ACER_AMW0_V2:
+               case ACER_WMID:
+                       return WMID_set_u32(value, cap, interface);
+               default:
+                       return AE_BAD_PARAMETER;
+               }
+       }
+       return AE_BAD_PARAMETER;
+}
+
+static void __init acer_commandline_init(void)
+{
+       /*
+        * These will all fail silently if the value given is invalid, or the
+        * capability isn't available on the given interface
+        */
+       set_u32(mailled, ACER_CAP_MAILLED);
+       set_u32(wireless, ACER_CAP_WIRELESS);
+       set_u32(bluetooth, ACER_CAP_BLUETOOTH);
+       set_u32(threeg, ACER_CAP_THREEG);
+       set_u32(brightness, ACER_CAP_BRIGHTNESS);
+}
+
+/*
+ * LED device (Mail LED only, no other LEDs known yet)
+ */
+static void mail_led_set(struct led_classdev *led_cdev,
+enum led_brightness value)
+{
+       set_u32(value, ACER_CAP_MAILLED);
+}
+
+static struct led_classdev mail_led = {
+       .name = "acer-mail:green",
+       .brightness_set = mail_led_set,
+};
+
+static int __init acer_led_init(struct device *dev)
+{
+       return led_classdev_register(dev, &mail_led);
+}
+
+static void acer_led_exit(void)
+{
+       led_classdev_unregister(&mail_led);
+}
+
+/*
+ * Backlight device
+ */
+static struct backlight_device *acer_backlight_device;
+
+static int read_brightness(struct backlight_device *bd)
+{
+       u32 value;
+       get_u32(&value, ACER_CAP_BRIGHTNESS);
+       return value;
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+       set_u32(bd->props.brightness, ACER_CAP_BRIGHTNESS);
+       return 0;
+}
+
+static struct backlight_ops acer_bl_ops = {
+       .get_brightness = read_brightness,
+       .update_status = update_bl_status,
+};
+
+static int __init acer_backlight_init(struct device *dev)
+{
+       struct backlight_device *bd;
+
+       bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops);
+       if (IS_ERR(bd)) {
+               printk(ACER_ERR "Could not register Acer backlight device\n");
+               acer_backlight_device = NULL;
+               return PTR_ERR(bd);
+       }
+
+       acer_backlight_device = bd;
+
+       bd->props.max_brightness = max_brightness;
+       bd->props.brightness = read_brightness(NULL);
+       backlight_update_status(bd);
+       return 0;
+}
+
+static void __exit acer_backlight_exit(void)
+{
+       backlight_device_unregister(acer_backlight_device);
+}
+
+/*
+ * Read/ write bool sysfs macro
+ */
+#define show_set_bool(value, cap) \
+static ssize_t \
+show_bool_##value(struct device *dev, struct device_attribute *attr, \
+       char *buf) \
+{ \
+       u32 result; \
+       acpi_status status = get_u32(&result, cap); \
+       if (ACPI_SUCCESS(status)) \
+               return sprintf(buf, "%u\n", result); \
+       return sprintf(buf, "Read error\n"); \
+} \
+\
+static ssize_t \
+set_bool_##value(struct device *dev, struct device_attribute *attr, \
+       const char *buf, size_t count) \
+{ \
+       u32 tmp = simple_strtoul(buf, NULL, 10); \
+       acpi_status status = set_u32(tmp, cap); \
+               if (ACPI_FAILURE(status)) \
+                       return -EINVAL; \
+       return count; \
+} \
+static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
+       show_bool_##value, set_bool_##value);
+
+show_set_bool(wireless, ACER_CAP_WIRELESS);
+show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
+show_set_bool(threeg, ACER_CAP_THREEG);
+
+/*
+ * Read interface sysfs macro
+ */
+static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
+       char *buf)
+{
+       switch (interface->type) {
+       case ACER_AMW0:
+               return sprintf(buf, "AMW0\n");
+       case ACER_AMW0_V2:
+               return sprintf(buf, "AMW0 v2\n");
+       case ACER_WMID:
+               return sprintf(buf, "WMID\n");
+       default:
+               return sprintf(buf, "Error!\n");
+       }
+}
+
+static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR,
+       show_interface, NULL);
+
+/*
+ * Platform device
+ */
+static int __devinit acer_platform_probe(struct platform_device *device)
+{
+       int err;
+
+       if (has_cap(ACER_CAP_MAILLED)) {
+               err = acer_led_init(&device->dev);
+               if (err)
+                       goto error_mailled;
+       }
+
+       if (has_cap(ACER_CAP_BRIGHTNESS)) {
+               err = acer_backlight_init(&device->dev);
+               if (err)
+                       goto error_brightness;
+       }
+
+       return 0;
+
+error_brightness:
+       acer_led_exit();
+error_mailled:
+       return err;
+}
+
+static int acer_platform_remove(struct platform_device *device)
+{
+       if (has_cap(ACER_CAP_MAILLED))
+               acer_led_exit();
+       if (has_cap(ACER_CAP_BRIGHTNESS))
+               acer_backlight_exit();
+       return 0;
+}
+
+static int acer_platform_suspend(struct platform_device *dev,
+pm_message_t state)
+{
+       u32 value;
+       struct acer_data *data = &interface->data;
+
+       if (!data)
+               return -ENOMEM;
+
+       if (has_cap(ACER_CAP_WIRELESS)) {
+               get_u32(&value, ACER_CAP_WIRELESS);
+               data->wireless = value;
+       }
+
+       if (has_cap(ACER_CAP_BLUETOOTH)) {
+               get_u32(&value, ACER_CAP_BLUETOOTH);
+               data->bluetooth = value;
+       }
+
+       if (has_cap(ACER_CAP_MAILLED)) {
+               get_u32(&value, ACER_CAP_MAILLED);
+               data->mailled = value;
+       }
+
+       if (has_cap(ACER_CAP_BRIGHTNESS)) {
+               get_u32(&value, ACER_CAP_BRIGHTNESS);
+               data->brightness = value;
+       }
+
+       return 0;
+}
+
+static int acer_platform_resume(struct platform_device *device)
+{
+       struct acer_data *data = &interface->data;
+
+       if (!data)
+               return -ENOMEM;
+
+       if (has_cap(ACER_CAP_WIRELESS))
+               set_u32(data->wireless, ACER_CAP_WIRELESS);
+
+       if (has_cap(ACER_CAP_BLUETOOTH))
+               set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
+
+       if (has_cap(ACER_CAP_THREEG))
+               set_u32(data->threeg, ACER_CAP_THREEG);
+
+       if (has_cap(ACER_CAP_MAILLED))
+               set_u32(data->mailled, ACER_CAP_MAILLED);
+
+       if (has_cap(ACER_CAP_BRIGHTNESS))
+               set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
+
+       return 0;
+}
+
+static struct platform_driver acer_platform_driver = {
+       .driver = {
+               .name = "acer-wmi",
+               .owner = THIS_MODULE,
+       },
+       .probe = acer_platform_probe,
+       .remove = acer_platform_remove,
+       .suspend = acer_platform_suspend,
+       .resume = acer_platform_resume,
+};
+
+static struct platform_device *acer_platform_device;
+
+static int remove_sysfs(struct platform_device *device)
+{
+       if (has_cap(ACER_CAP_WIRELESS))
+               device_remove_file(&device->dev, &dev_attr_wireless);
+
+       if (has_cap(ACER_CAP_BLUETOOTH))
+               device_remove_file(&device->dev, &dev_attr_bluetooth);
+
+       if (has_cap(ACER_CAP_THREEG))
+               device_remove_file(&device->dev, &dev_attr_threeg);
+
+       device_remove_file(&device->dev, &dev_attr_interface);
+
+       return 0;
+}
+
+static int create_sysfs(void)
+{
+       int retval = -ENOMEM;
+
+       if (has_cap(ACER_CAP_WIRELESS)) {
+               retval = device_create_file(&acer_platform_device->dev,
+                       &dev_attr_wireless);
+               if (retval)
+                       goto error_sysfs;
+       }
+
+       if (has_cap(ACER_CAP_BLUETOOTH)) {
+               retval = device_create_file(&acer_platform_device->dev,
+                       &dev_attr_bluetooth);
+               if (retval)
+                       goto error_sysfs;
+       }
+
+       if (has_cap(ACER_CAP_THREEG)) {
+               retval = device_create_file(&acer_platform_device->dev,
+                       &dev_attr_threeg);
+               if (retval)
+                       goto error_sysfs;
+       }
+
+       retval = device_create_file(&acer_platform_device->dev,
+               &dev_attr_interface);
+       if (retval)
+               goto error_sysfs;
+
+       return 0;
+
+error_sysfs:
+               remove_sysfs(acer_platform_device);
+       return retval;
+}
+
+static int __init acer_wmi_init(void)
+{
+       int err;
+
+       printk(ACER_INFO "Acer Laptop ACPI-WMI Extras version %s\n",
+                       ACER_WMI_VERSION);
+
+       /*
+        * Detect which ACPI-WMI interface we're using.
+        */
+       if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
+               interface = &AMW0_V2_interface;
+
+       if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
+               interface = &wmid_interface;
+
+       if (wmi_has_guid(WMID_GUID2) && interface) {
+               if (ACPI_FAILURE(WMID_set_capabilities())) {
+                       printk(ACER_ERR "Unable to detect available devices\n");
+                       return -ENODEV;
+               }
+       } else if (!wmi_has_guid(WMID_GUID2) && interface) {
+               printk(ACER_ERR "Unable to detect available devices\n");
+               return -ENODEV;
+       }
+
+       if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
+               interface = &AMW0_interface;
+
+               if (ACPI_FAILURE(AMW0_set_capabilities())) {
+                       printk(ACER_ERR "Unable to detect available devices\n");
+                       return -ENODEV;
+               }
+       }
+
+       if (wmi_has_guid(AMW0_GUID1)) {
+               if (ACPI_FAILURE(AMW0_find_mailled()))
+                       printk(ACER_ERR "Unable to detect mail LED\n");
+       }
+
+       find_quirks();
+
+       if (!interface) {
+               printk(ACER_ERR "No or unsupported WMI interface, unable to ");
+               printk(KERN_CONT "load.\n");
+               return -ENODEV;
+       }
+
+       if (platform_driver_register(&acer_platform_driver)) {
+               printk(ACER_ERR "Unable to register platform driver.\n");
+               goto error_platform_register;
+       }
+       acer_platform_device = platform_device_alloc("acer-wmi", -1);
+       platform_device_add(acer_platform_device);
+
+       err = create_sysfs();
+       if (err)
+               return err;
+
+       /* Override any initial settings with values from the commandline */
+       acer_commandline_init();
+
+       return 0;
+
+error_platform_register:
+       return -ENODEV;
+}
+
+static void __exit acer_wmi_exit(void)
+{
+       remove_sysfs(acer_platform_device);
+       platform_device_del(acer_platform_device);
+       platform_driver_unregister(&acer_platform_driver);
+
+       printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
+       return;
+}
+
+module_init(acer_wmi_init);
+module_exit(acer_wmi_exit);
index 0846c33296bc7e1a0da8aabf21a7023667613edb..7c6dfd03de9fc9db3a6295f2751ed046f7cac845 100644 (file)
@@ -239,7 +239,7 @@ static struct workqueue_struct *led_workqueue;
        static int object##_led_wk;                                     \
        static DECLARE_WORK(object##_led_work, object##_led_update);    \
        static struct led_classdev object##_led = {                     \
-               .name           = "asus:" ledname,                      \
+               .name           = "asus::" ledname,                     \
                .brightness_set = object##_led_set,                     \
        }
 
@@ -254,7 +254,7 @@ ASUS_LED(gled, "gaming");
  * method is searched within the scope of the handle, can be NULL. The output
  * of the method is written is output, which can also be NULL
  *
- * returns 1 if write is successful, 0 else.
+ * returns 0 if write is successful, -1 else.
  */
 static int write_acpi_int(acpi_handle handle, const char *method, int val,
                          struct acpi_buffer *output)
@@ -263,13 +263,19 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
        union acpi_object in_obj;       //the only param we use
        acpi_status status;
 
+       if (!handle)
+               return 0;
+
        params.count = 1;
        params.pointer = &in_obj;
        in_obj.type = ACPI_TYPE_INTEGER;
        in_obj.integer.value = val;
 
        status = acpi_evaluate_object(handle, (char *)method, &params, output);
-       return (status == AE_OK);
+       if (status == AE_OK)
+               return 0;
+       else
+               return -1;
 }
 
 static int read_wireless_status(int mask)
@@ -321,7 +327,7 @@ static void write_status(acpi_handle handle, int out, int mask)
 
        switch (mask) {
        case MLED_ON:
-               out = !out & 0x1;
+               out = !(out & 0x1);
                break;
        case GLED_ON:
                out = (out & 0x1) + 1;
@@ -335,7 +341,7 @@ static void write_status(acpi_handle handle, int out, int mask)
                break;
        }
 
-       if (handle && !write_acpi_int(handle, NULL, out, NULL))
+       if (write_acpi_int(handle, NULL, out, NULL))
                printk(ASUS_WARNING " write failed %x\n", mask);
 }
 
@@ -415,7 +421,7 @@ static int set_brightness(struct backlight_device *bd, int value)
        value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
        /* 0 <= value <= 15 */
 
-       if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
+       if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
                printk(ASUS_WARNING "Error changing brightness\n");
                ret = -EIO;
        }
@@ -545,7 +551,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
 
        rv = parse_arg(buf, count, &value);
        if (rv > 0) {
-               if (!write_acpi_int(ledd_set_handle, NULL, value, NULL))
+               if (write_acpi_int(ledd_set_handle, NULL, value, NULL))
                        printk(ASUS_WARNING "LED display write failed\n");
                else
                        hotk->ledd_status = (u32) value;
@@ -590,7 +596,7 @@ static ssize_t store_bluetooth(struct device *dev,
 static void set_display(int value)
 {
        /* no sanity check needed for now */
-       if (!write_acpi_int(display_set_handle, NULL, value, NULL))
+       if (write_acpi_int(display_set_handle, NULL, value, NULL))
                printk(ASUS_WARNING "Error setting display\n");
        return;
 }
@@ -647,7 +653,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
  */
 static void set_light_sens_switch(int value)
 {
-       if (!write_acpi_int(ls_switch_handle, NULL, value, NULL))
+       if (write_acpi_int(ls_switch_handle, NULL, value, NULL))
                printk(ASUS_WARNING "Error setting light sensor switch\n");
        hotk->light_switch = value;
 }
@@ -672,7 +678,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
 
 static void set_light_sens_level(int value)
 {
-       if (!write_acpi_int(ls_level_handle, NULL, value, NULL))
+       if (write_acpi_int(ls_level_handle, NULL, value, NULL))
                printk(ASUS_WARNING "Error setting light sensor level\n");
        hotk->light_level = value;
 }
@@ -860,7 +866,7 @@ static int asus_hotk_get_info(void)
                printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
 
        /* We have to write 0 on init this far for all ASUS models */
-       if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+       if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
                printk(ASUS_ERR "Hotkey initialization failed\n");
                return -ENODEV;
        }
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
new file mode 100644 (file)
index 0000000..f70984a
--- /dev/null
@@ -0,0 +1,526 @@
+/*
+ *  intel_menlow.c - Intel menlow Driver for thermal management extension
+ *
+ *  Copyright (C) 2008 Intel Corp
+ *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This driver creates the sys I/F for programming the sensors.
+ *  It also implements the driver for intel menlow memory controller (hardware
+ *  id is INT0002) which makes use of the platform specific ACPI methods
+ *  to get/set bandwidth.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+
+#include <linux/thermal.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Thomas Sujith");
+MODULE_AUTHOR("Zhang Rui");
+MODULE_DESCRIPTION("Intel Menlow platform specific driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Memory controller device control
+ */
+
+#define MEMORY_GET_BANDWIDTH "GTHS"
+#define MEMORY_SET_BANDWIDTH "STHS"
+#define MEMORY_ARG_CUR_BANDWIDTH 1
+#define MEMORY_ARG_MAX_BANDWIDTH 0
+
+static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
+                                       unsigned long *max_state)
+{
+       struct acpi_device *device = cdev->devdata;
+       acpi_handle handle = device->handle;
+       unsigned long value;
+       struct acpi_object_list arg_list;
+       union acpi_object arg;
+       acpi_status status = AE_OK;
+
+       arg_list.count = 1;
+       arg_list.pointer = &arg;
+       arg.type = ACPI_TYPE_INTEGER;
+       arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH;
+       status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
+                                      &arg_list, &value);
+       if (ACPI_FAILURE(status))
+               return -EFAULT;
+
+       *max_state = value - 1;
+       return 0;
+}
+
+static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
+                                   char *buf)
+{
+       unsigned long value;
+       if (memory_get_int_max_bandwidth(cdev, &value))
+               return -EINVAL;
+
+       return sprintf(buf, "%ld\n", value);
+}
+
+static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
+                                   char *buf)
+{
+       struct acpi_device *device = cdev->devdata;
+       acpi_handle handle = device->handle;
+       unsigned long value;
+       struct acpi_object_list arg_list;
+       union acpi_object arg;
+       acpi_status status = AE_OK;
+
+       arg_list.count = 1;
+       arg_list.pointer = &arg;
+       arg.type = ACPI_TYPE_INTEGER;
+       arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
+       status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
+                                      &arg_list, &value);
+       if (ACPI_FAILURE(status))
+               return -EFAULT;
+
+       return sprintf(buf, "%ld\n", value);
+}
+
+static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
+                                   unsigned int state)
+{
+       struct acpi_device *device = cdev->devdata;
+       acpi_handle handle = device->handle;
+       struct acpi_object_list arg_list;
+       union acpi_object arg;
+       acpi_status status;
+       int temp;
+       unsigned long max_state;
+
+       if (memory_get_int_max_bandwidth(cdev, &max_state))
+               return -EFAULT;
+
+       if (max_state < 0 || state > max_state)
+               return -EINVAL;
+
+       arg_list.count = 1;
+       arg_list.pointer = &arg;
+       arg.type = ACPI_TYPE_INTEGER;
+       arg.integer.value = state;
+
+       status =
+           acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
+                                 (unsigned long *)&temp);
+
+       printk(KERN_INFO
+              "Bandwidth value was %d: status is %d\n", state, status);
+       if (ACPI_FAILURE(status))
+               return -EFAULT;
+
+       return 0;
+}
+
+static struct thermal_cooling_device_ops memory_cooling_ops = {
+       .get_max_state = memory_get_max_bandwidth,
+       .get_cur_state = memory_get_cur_bandwidth,
+       .set_cur_state = memory_set_cur_bandwidth,
+};
+
+/*
+ * Memory Device Management
+ */
+static int intel_menlow_memory_add(struct acpi_device *device)
+{
+       int result = -ENODEV;
+       acpi_status status = AE_OK;
+       acpi_handle dummy;
+       struct thermal_cooling_device *cdev;
+
+       if (!device)
+               return -EINVAL;
+
+       status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy);
+       if (ACPI_FAILURE(status))
+               goto end;
+
+       status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy);
+       if (ACPI_FAILURE(status))
+               goto end;
+
+       cdev = thermal_cooling_device_register("Memory controller", device,
+                                              &memory_cooling_ops);
+       acpi_driver_data(device) = cdev;
+       if (!cdev)
+               result = -ENODEV;
+       else {
+               result = sysfs_create_link(&device->dev.kobj,
+                                       &cdev->device.kobj, "thermal_cooling");
+               if (result)
+                       goto unregister;
+
+               result = sysfs_create_link(&cdev->device.kobj,
+                                       &device->dev.kobj, "device");
+               if (result) {
+                       sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+                       goto unregister;
+               }
+       }
+
+ end:
+       return result;
+
+ unregister:
+       thermal_cooling_device_unregister(cdev);
+       return result;
+
+}
+
+static int intel_menlow_memory_remove(struct acpi_device *device, int type)
+{
+       struct thermal_cooling_device *cdev = acpi_driver_data(device);
+
+       if (!device || !cdev)
+               return -EINVAL;
+
+       sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+       sysfs_remove_link(&cdev->device.kobj, "device");
+       thermal_cooling_device_unregister(cdev);
+
+       return 0;
+}
+
+const static struct acpi_device_id intel_menlow_memory_ids[] = {
+       {"INT0002", 0},
+       {"", 0},
+};
+
+static struct acpi_driver intel_menlow_memory_driver = {
+       .name = "intel_menlow_thermal_control",
+       .ids = intel_menlow_memory_ids,
+       .ops = {
+               .add = intel_menlow_memory_add,
+               .remove = intel_menlow_memory_remove,
+               },
+};
+
+/*
+ * Sensor control on menlow platform
+ */
+
+#define THERMAL_AUX0 0
+#define THERMAL_AUX1 1
+#define GET_AUX0 "GAX0"
+#define GET_AUX1 "GAX1"
+#define SET_AUX0 "SAX0"
+#define SET_AUX1 "SAX1"
+
+struct intel_menlow_attribute {
+       struct device_attribute attr;
+       struct device *device;
+       acpi_handle handle;
+       struct list_head node;
+};
+
+static LIST_HEAD(intel_menlow_attr_list);
+static DEFINE_MUTEX(intel_menlow_attr_lock);
+
+/*
+ * sensor_get_auxtrip - get the current auxtrip value from sensor
+ * @name: Thermalzone name
+ * @auxtype : AUX0/AUX1
+ * @buf: syfs buffer
+ */
+static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
+{
+       acpi_status status;
+
+       if ((index != 0 && index != 1) || !value)
+               return -EINVAL;
+
+       status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
+                                      NULL, (unsigned long *)value);
+       if (ACPI_FAILURE(status))
+               return -EIO;
+
+       return 0;
+}
+
+/*
+ * sensor_set_auxtrip - set the new auxtrip value to sensor
+ * @name: Thermalzone name
+ * @auxtype : AUX0/AUX1
+ * @buf: syfs buffer
+ */
+static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
+{
+       acpi_status status;
+       union acpi_object arg = {
+               ACPI_TYPE_INTEGER
+       };
+       struct acpi_object_list args = {
+               1, &arg
+       };
+       int temp;
+
+       if (index != 0 && index != 1)
+               return -EINVAL;
+
+       status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
+                                      NULL, (unsigned long *)&temp);
+       if (ACPI_FAILURE(status))
+               return -EIO;
+       if ((index && value < temp) || (!index && value > temp))
+               return -EINVAL;
+
+       arg.integer.value = value;
+       status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
+                                      &args, (unsigned long *)&temp);
+       if (ACPI_FAILURE(status))
+               return -EIO;
+
+       /* do we need to check the return value of SAX0/SAX1 ? */
+
+       return 0;
+}
+
+#define to_intel_menlow_attr(_attr)    \
+       container_of(_attr, struct intel_menlow_attribute, attr)
+
+static ssize_t aux0_show(struct device *dev,
+                        struct device_attribute *dev_attr, char *buf)
+{
+       struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
+       int value;
+       int result;
+
+       result = sensor_get_auxtrip(attr->handle, 0, &value);
+
+       return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
+}
+
+static ssize_t aux1_show(struct device *dev,
+                        struct device_attribute *dev_attr, char *buf)
+{
+       struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
+       int value;
+       int result;
+
+       result = sensor_get_auxtrip(attr->handle, 1, &value);
+
+       return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
+}
+
+static ssize_t aux0_store(struct device *dev,
+                         struct device_attribute *dev_attr,
+                         const char *buf, size_t count)
+{
+       struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
+       int value;
+       int result;
+
+       /*Sanity check; should be a positive integer */
+       if (!sscanf(buf, "%d", &value))
+               return -EINVAL;
+
+       if (value < 0)
+               return -EINVAL;
+
+       result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value));
+       return result ? result : count;
+}
+
+static ssize_t aux1_store(struct device *dev,
+                         struct device_attribute *dev_attr,
+                         const char *buf, size_t count)
+{
+       struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
+       int value;
+       int result;
+
+       /*Sanity check; should be a positive integer */
+       if (!sscanf(buf, "%d", &value))
+               return -EINVAL;
+
+       if (value < 0)
+               return -EINVAL;
+
+       result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value));
+       return result ? result : count;
+}
+
+/* BIOS can enable/disable the thermal user application in dabney platform */
+#define BIOS_ENABLED "\\_TZ.GSTS"
+static ssize_t bios_enabled_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       acpi_status status;
+       unsigned long bios_enabled;
+
+       status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled");
+}
+
+static int intel_menlow_add_one_attribute(char *name, int mode, void *show,
+                                         void *store, struct device *dev,
+                                         acpi_handle handle)
+{
+       struct intel_menlow_attribute *attr;
+       int result;
+
+       attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL);
+       if (!attr)
+               return -ENOMEM;
+
+       attr->attr.attr.name = name;
+       attr->attr.attr.mode = mode;
+       attr->attr.show = show;
+       attr->attr.store = store;
+       attr->device = dev;
+       attr->handle = handle;
+
+       result = device_create_file(dev, &attr->attr);
+       if (result)
+               return result;
+
+       mutex_lock(&intel_menlow_attr_lock);
+       list_add_tail(&attr->node, &intel_menlow_attr_list);
+       mutex_unlock(&intel_menlow_attr_lock);
+
+       return 0;
+}
+
+static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
+                                               void *context, void **rv)
+{
+       acpi_status status;
+       acpi_handle dummy;
+       struct thermal_zone_device *thermal;
+       int result;
+
+       result = acpi_bus_get_private_data(handle, (void **)&thermal);
+       if (result)
+               return 0;
+
+       /* _TZ must have the AUX0/1 methods */
+       status = acpi_get_handle(handle, GET_AUX0, &dummy);
+       if (ACPI_FAILURE(status))
+               goto not_found;
+
+       status = acpi_get_handle(handle, SET_AUX0, &dummy);
+       if (ACPI_FAILURE(status))
+               goto not_found;
+
+       result = intel_menlow_add_one_attribute("aux0", 0644,
+                                               aux0_show, aux0_store,
+                                               &thermal->device, handle);
+       if (result)
+               return AE_ERROR;
+
+       status = acpi_get_handle(handle, GET_AUX1, &dummy);
+       if (ACPI_FAILURE(status))
+               goto not_found;
+
+       status = acpi_get_handle(handle, SET_AUX1, &dummy);
+       if (ACPI_FAILURE(status))
+               goto not_found;
+
+       result = intel_menlow_add_one_attribute("aux1", 0644,
+                                               aux1_show, aux1_store,
+                                               &thermal->device, handle);
+       if (result)
+               return AE_ERROR;
+
+       /*
+        * create the "dabney_enabled" attribute which means the user app
+        * should be loaded or not
+        */
+
+       result = intel_menlow_add_one_attribute("bios_enabled", 0444,
+                                               bios_enabled_show, NULL,
+                                               &thermal->device, handle);
+       if (result)
+               return AE_ERROR;
+
+ not_found:
+       if (status == AE_NOT_FOUND)
+               return AE_OK;
+       else
+               return status;
+}
+
+static void intel_menlow_unregister_sensor(void)
+{
+       struct intel_menlow_attribute *pos, *next;
+
+       mutex_lock(&intel_menlow_attr_lock);
+       list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) {
+               list_del(&pos->node);
+               device_remove_file(pos->device, &pos->attr);
+               kfree(pos);
+       }
+       mutex_unlock(&intel_menlow_attr_lock);
+
+       return;
+}
+
+static int __init intel_menlow_module_init(void)
+{
+       int result = -ENODEV;
+       acpi_status status;
+       unsigned long enable;
+
+       if (acpi_disabled)
+               return result;
+
+       /* Looking for the \_TZ.GSTS method */
+       status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable);
+       if (ACPI_FAILURE(status) || !enable)
+               return -ENODEV;
+
+       /* Looking for ACPI device MEM0 with hardware id INT0002 */
+       result = acpi_bus_register_driver(&intel_menlow_memory_driver);
+       if (result)
+               return result;
+
+       /* Looking for sensors in each ACPI thermal zone */
+       status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
+                                    ACPI_UINT32_MAX,
+                                    intel_menlow_register_sensor, NULL, NULL);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit intel_menlow_module_exit(void)
+{
+       acpi_bus_unregister_driver(&intel_menlow_memory_driver);
+       intel_menlow_unregister_sensor();
+}
+
+module_init(intel_menlow_module_init);
+module_exit(intel_menlow_module_exit);
index b0f68031b49dfa926dd8ccc62ff91d058638a65a..899e3f75f288dd853a50f61e9c15772ea3d60b01 100644 (file)
@@ -73,7 +73,7 @@
        if (debug) printk(KERN_WARNING DRV_PFX  msg);   \
 } while (0)
 
-#define SONY_LAPTOP_DRIVER_VERSION     "0.5"
+#define SONY_LAPTOP_DRIVER_VERSION     "0.6"
 
 #define SONY_NC_CLASS          "sony-nc"
 #define SONY_NC_HID            "SNY5001"
@@ -146,68 +146,70 @@ struct sony_laptop_keypress {
  * and input layer indexes in the keymap
  */
 static int sony_laptop_input_index[] = {
-       -1,     /* no event */
-       -1,     /* SONYPI_EVENT_JOGDIAL_DOWN */
-       -1,     /* SONYPI_EVENT_JOGDIAL_UP */
-       -1,     /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
-       -1,     /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
-       -1,     /* SONYPI_EVENT_JOGDIAL_PRESSED */
-       -1,     /* SONYPI_EVENT_JOGDIAL_RELEASED */
-        0,     /* SONYPI_EVENT_CAPTURE_PRESSED */
-        1,     /* SONYPI_EVENT_CAPTURE_RELEASED */
-        2,     /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
-        3,     /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
-        4,     /* SONYPI_EVENT_FNKEY_ESC */
-        5,     /* SONYPI_EVENT_FNKEY_F1 */
-        6,     /* SONYPI_EVENT_FNKEY_F2 */
-        7,     /* SONYPI_EVENT_FNKEY_F3 */
-        8,     /* SONYPI_EVENT_FNKEY_F4 */
-        9,     /* SONYPI_EVENT_FNKEY_F5 */
-       10,     /* SONYPI_EVENT_FNKEY_F6 */
-       11,     /* SONYPI_EVENT_FNKEY_F7 */
-       12,     /* SONYPI_EVENT_FNKEY_F8 */
-       13,     /* SONYPI_EVENT_FNKEY_F9 */
-       14,     /* SONYPI_EVENT_FNKEY_F10 */
-       15,     /* SONYPI_EVENT_FNKEY_F11 */
-       16,     /* SONYPI_EVENT_FNKEY_F12 */
-       17,     /* SONYPI_EVENT_FNKEY_1 */
-       18,     /* SONYPI_EVENT_FNKEY_2 */
-       19,     /* SONYPI_EVENT_FNKEY_D */
-       20,     /* SONYPI_EVENT_FNKEY_E */
-       21,     /* SONYPI_EVENT_FNKEY_F */
-       22,     /* SONYPI_EVENT_FNKEY_S */
-       23,     /* SONYPI_EVENT_FNKEY_B */
-       24,     /* SONYPI_EVENT_BLUETOOTH_PRESSED */
-       25,     /* SONYPI_EVENT_PKEY_P1 */
-       26,     /* SONYPI_EVENT_PKEY_P2 */
-       27,     /* SONYPI_EVENT_PKEY_P3 */
-       28,     /* SONYPI_EVENT_BACK_PRESSED */
-       -1,     /* SONYPI_EVENT_LID_CLOSED */
-       -1,     /* SONYPI_EVENT_LID_OPENED */
-       29,     /* SONYPI_EVENT_BLUETOOTH_ON */
-       30,     /* SONYPI_EVENT_BLUETOOTH_OFF */
-       31,     /* SONYPI_EVENT_HELP_PRESSED */
-       32,     /* SONYPI_EVENT_FNKEY_ONLY */
-       33,     /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
-       34,     /* SONYPI_EVENT_JOGDIAL_FAST_UP */
-       35,     /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
-       36,     /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
-       37,     /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
-       38,     /* SONYPI_EVENT_JOGDIAL_VFAST_UP */
-       39,     /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
-       40,     /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
-       41,     /* SONYPI_EVENT_ZOOM_PRESSED */
-       42,     /* SONYPI_EVENT_THUMBPHRASE_PRESSED */
-       43,     /* SONYPI_EVENT_MEYE_FACE */
-       44,     /* SONYPI_EVENT_MEYE_OPPOSITE */
-       45,     /* SONYPI_EVENT_MEMORYSTICK_INSERT */
-       46,     /* SONYPI_EVENT_MEMORYSTICK_EJECT */
-       -1,     /* SONYPI_EVENT_ANYBUTTON_RELEASED */
-       -1,     /* SONYPI_EVENT_BATTERY_INSERT */
-       -1,     /* SONYPI_EVENT_BATTERY_REMOVE */
-       -1,     /* SONYPI_EVENT_FNKEY_RELEASED */
-       47,     /* SONYPI_EVENT_WIRELESS_ON */
-       48,     /* SONYPI_EVENT_WIRELESS_OFF */
+       -1,     /*  0 no event */
+       -1,     /*  1 SONYPI_EVENT_JOGDIAL_DOWN */
+       -1,     /*  2 SONYPI_EVENT_JOGDIAL_UP */
+       -1,     /*  3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
+       -1,     /*  4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
+       -1,     /*  5 SONYPI_EVENT_JOGDIAL_PRESSED */
+       -1,     /*  6 SONYPI_EVENT_JOGDIAL_RELEASED */
+        0,     /*  7 SONYPI_EVENT_CAPTURE_PRESSED */
+        1,     /*  8 SONYPI_EVENT_CAPTURE_RELEASED */
+        2,     /*  9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+        3,     /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+        4,     /* 11 SONYPI_EVENT_FNKEY_ESC */
+        5,     /* 12 SONYPI_EVENT_FNKEY_F1 */
+        6,     /* 13 SONYPI_EVENT_FNKEY_F2 */
+        7,     /* 14 SONYPI_EVENT_FNKEY_F3 */
+        8,     /* 15 SONYPI_EVENT_FNKEY_F4 */
+        9,     /* 16 SONYPI_EVENT_FNKEY_F5 */
+       10,     /* 17 SONYPI_EVENT_FNKEY_F6 */
+       11,     /* 18 SONYPI_EVENT_FNKEY_F7 */
+       12,     /* 19 SONYPI_EVENT_FNKEY_F8 */
+       13,     /* 20 SONYPI_EVENT_FNKEY_F9 */
+       14,     /* 21 SONYPI_EVENT_FNKEY_F10 */
+       15,     /* 22 SONYPI_EVENT_FNKEY_F11 */
+       16,     /* 23 SONYPI_EVENT_FNKEY_F12 */
+       17,     /* 24 SONYPI_EVENT_FNKEY_1 */
+       18,     /* 25 SONYPI_EVENT_FNKEY_2 */
+       19,     /* 26 SONYPI_EVENT_FNKEY_D */
+       20,     /* 27 SONYPI_EVENT_FNKEY_E */
+       21,     /* 28 SONYPI_EVENT_FNKEY_F */
+       22,     /* 29 SONYPI_EVENT_FNKEY_S */
+       23,     /* 30 SONYPI_EVENT_FNKEY_B */
+       24,     /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
+       25,     /* 32 SONYPI_EVENT_PKEY_P1 */
+       26,     /* 33 SONYPI_EVENT_PKEY_P2 */
+       27,     /* 34 SONYPI_EVENT_PKEY_P3 */
+       28,     /* 35 SONYPI_EVENT_BACK_PRESSED */
+       -1,     /* 36 SONYPI_EVENT_LID_CLOSED */
+       -1,     /* 37 SONYPI_EVENT_LID_OPENED */
+       29,     /* 38 SONYPI_EVENT_BLUETOOTH_ON */
+       30,     /* 39 SONYPI_EVENT_BLUETOOTH_OFF */
+       31,     /* 40 SONYPI_EVENT_HELP_PRESSED */
+       32,     /* 41 SONYPI_EVENT_FNKEY_ONLY */
+       33,     /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+       34,     /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
+       35,     /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+       36,     /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+       37,     /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+       38,     /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
+       39,     /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+       40,     /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+       41,     /* 50 SONYPI_EVENT_ZOOM_PRESSED */
+       42,     /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
+       43,     /* 52 SONYPI_EVENT_MEYE_FACE */
+       44,     /* 53 SONYPI_EVENT_MEYE_OPPOSITE */
+       45,     /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
+       46,     /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
+       -1,     /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
+       -1,     /* 57 SONYPI_EVENT_BATTERY_INSERT */
+       -1,     /* 58 SONYPI_EVENT_BATTERY_REMOVE */
+       -1,     /* 59 SONYPI_EVENT_FNKEY_RELEASED */
+       47,     /* 60 SONYPI_EVENT_WIRELESS_ON */
+       48,     /* 61 SONYPI_EVENT_WIRELESS_OFF */
+       49,     /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */
+       50,     /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */
 };
 
 static int sony_laptop_input_keycode_map[] = {
@@ -260,6 +262,8 @@ static int sony_laptop_input_keycode_map[] = {
        KEY_RESERVED,   /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
        KEY_WLAN,       /* 47 SONYPI_EVENT_WIRELESS_ON */
        KEY_WLAN,       /* 48 SONYPI_EVENT_WIRELESS_OFF */
+       KEY_ZOOMIN,     /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */
+       KEY_ZOOMOUT     /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */
 };
 
 /* release buttons after a short delay if pressed */
@@ -311,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event)
                break;
 
        default:
-               if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) {
+               if (event > ARRAY_SIZE(sony_laptop_input_index)) {
                        dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
                        break;
                }
@@ -875,6 +879,15 @@ static const struct dmi_system_id sony_nc_ids[] = {
                                DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
                        },
                },
+               {
+                       .ident = "Sony Vaio N Series",
+                       .callback = sony_nc_C_enable,
+                       .driver_data = sony_C_events,
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"),
+                       },
+               },
                { }
 };
 
@@ -1169,10 +1182,12 @@ static struct acpi_driver sony_nc_driver = {
 #define SONYPI_DEVICE_TYPE1    0x00000001
 #define SONYPI_DEVICE_TYPE2    0x00000002
 #define SONYPI_DEVICE_TYPE3    0x00000004
+#define SONYPI_DEVICE_TYPE4    0x00000008
 
 #define SONYPI_TYPE1_OFFSET    0x04
 #define SONYPI_TYPE2_OFFSET    0x12
 #define SONYPI_TYPE3_OFFSET    0x12
+#define SONYPI_TYPE4_OFFSET    0x12
 
 struct sony_pic_ioport {
        struct acpi_resource_io io1;
@@ -1185,18 +1200,33 @@ struct sony_pic_irq {
        struct list_head                list;
 };
 
+struct sonypi_eventtypes {
+       u8                      data;
+       unsigned long           mask;
+       struct sonypi_event     *events;
+};
+
+struct device_ctrl {
+       int                             model;
+       int                             (*handle_irq)(const u8, const u8);
+       u16                             evport_offset;
+       u8                              has_camera;
+       u8                              has_bluetooth;
+       u8                              has_wwan;
+       struct sonypi_eventtypes        *event_types;
+};
+
 struct sony_pic_dev {
-       int                     model;
-       u16                     evport_offset;
-       u8                      camera_power;
-       u8                      bluetooth_power;
-       u8                      wwan_power;
+       struct device_ctrl      *control;
        struct acpi_device      *acpi_dev;
        struct sony_pic_irq     *cur_irq;
        struct sony_pic_ioport  *cur_ioport;
        struct list_head        interrupts;
        struct list_head        ioports;
        struct mutex            lock;
+       u8                      camera_power;
+       u8                      bluetooth_power;
+       u8                      wwan_power;
 };
 
 static struct sony_pic_dev spic_dev = {
@@ -1253,6 +1283,7 @@ static struct sonypi_event sonypi_joggerev[] = {
 static struct sonypi_event sonypi_captureev[] = {
        { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
        { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
+       { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
        { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
        { 0, 0 }
 };
@@ -1289,7 +1320,6 @@ static struct sonypi_event sonypi_pkeyev[] = {
        { 0x01, SONYPI_EVENT_PKEY_P1 },
        { 0x02, SONYPI_EVENT_PKEY_P2 },
        { 0x04, SONYPI_EVENT_PKEY_P3 },
-       { 0x5c, SONYPI_EVENT_PKEY_P1 },
        { 0, 0 }
 };
 
@@ -1331,6 +1361,8 @@ static struct sonypi_event sonypi_lidev[] = {
 /* The set of possible zoom events */
 static struct sonypi_event sonypi_zoomev[] = {
        { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+       { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
+       { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
        { 0, 0 }
 };
 
@@ -1361,76 +1393,58 @@ static struct sonypi_event sonypi_batteryev[] = {
        { 0, 0 }
 };
 
-static struct sonypi_eventtypes {
-       int                     model;
-       u8                      data;
-       unsigned long           mask;
-       struct sonypi_event *   events;
-} sony_pic_eventtypes[] = {
-       { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev },
-       { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
-       { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
-       { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
-       { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
-       { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
-       { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
-       { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
-       { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
-       { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
-
-       { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev },
-       { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
-       { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
-       { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
-       { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
-       { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
-       { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
-       { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
-       { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
-       { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
-       { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
-       { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
-       { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
-       { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
-
-       { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev },
-       { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
-       { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
-       { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
-       { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
-       { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
-       { 0 }
+static struct sonypi_eventtypes type1_events[] = {
+       { 0, 0xffffffff, sonypi_releaseev },
+       { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
+       { 0x30, SONYPI_LID_MASK, sonypi_lidev },
+       { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
+       { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
+       { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+       { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+       { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+       { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+       { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
+       { 0 },
+};
+static struct sonypi_eventtypes type2_events[] = {
+       { 0, 0xffffffff, sonypi_releaseev },
+       { 0x38, SONYPI_LID_MASK, sonypi_lidev },
+       { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
+       { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
+       { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+       { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+       { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
+       { 0x11, SONYPI_BACK_MASK, sonypi_backev },
+       { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
+       { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
+       { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
+       { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+       { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+       { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+       { 0 },
+};
+static struct sonypi_eventtypes type3_events[] = {
+       { 0, 0xffffffff, sonypi_releaseev },
+       { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+       { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+       { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+       { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+       { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+       { 0 },
+};
+static struct sonypi_eventtypes type4_events[] = {
+       { 0, 0xffffffff, sonypi_releaseev },
+       { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+       { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+       { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+       { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+       { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
+       { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
+       { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
+       { 0 },
 };
 
-static int sony_pic_detect_device_type(void)
-{
-       struct pci_dev *pcidev;
-       int model = 0;
-
-       if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                    PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
-               model = SONYPI_DEVICE_TYPE1;
-
-       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                         PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
-               model = SONYPI_DEVICE_TYPE3;
-
-       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                         PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
-               model = SONYPI_DEVICE_TYPE3;
-
-       else
-               model = SONYPI_DEVICE_TYPE2;
-
-       if (pcidev)
-               pci_dev_put(pcidev);
-
-       printk(KERN_INFO DRV_PFX "detected Type%d model\n",
-                       model == SONYPI_DEVICE_TYPE1 ? 1 :
-                       model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
-       return model;
-}
-
+/* low level spic calls */
 #define ITERATIONS_LONG                10000
 #define ITERATIONS_SHORT       10
 #define wait_on_command(command, iterations) {                         \
@@ -1451,7 +1465,7 @@ static u8 sony_pic_call1(u8 dev)
        outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
        v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
        v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
-       dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
+       dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
        return v2;
 }
 
@@ -1466,7 +1480,7 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
                        ITERATIONS_LONG);
        outb(fn, spic_dev.cur_ioport->io1.minimum);
        v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
-       dprintk("sony_pic_call2: 0x%.4x\n", v1);
+       dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
        return v1;
 }
 
@@ -1481,10 +1495,105 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
        wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
        outb(v, spic_dev.cur_ioport->io1.minimum);
        v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
-       dprintk("sony_pic_call3: 0x%.4x\n", v1);
+       dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
+                       dev, fn, v, v1);
        return v1;
 }
 
+/*
+ * minidrivers for SPIC models
+ */
+static int type4_handle_irq(const u8 data_mask, const u8 ev)
+{
+       /*
+        * 0x31 could mean we have to take some extra action and wait for
+        * the next irq for some Type4 models, it will generate a new
+        * irq and we can read new data from the device:
+        *  - 0x5c and 0x5f requires 0xA0
+        *  - 0x61 requires 0xB3
+        */
+       if (data_mask == 0x31) {
+               if (ev == 0x5c || ev == 0x5f)
+                       sony_pic_call1(0xA0);
+               else if (ev == 0x61)
+                       sony_pic_call1(0xB3);
+               return 0;
+       }
+       return 1;
+}
+
+static struct device_ctrl spic_types[] = {
+       {
+               .model = SONYPI_DEVICE_TYPE1,
+               .handle_irq = NULL,
+               .evport_offset = SONYPI_TYPE1_OFFSET,
+               .event_types = type1_events,
+       },
+       {
+               .model = SONYPI_DEVICE_TYPE2,
+               .handle_irq = NULL,
+               .evport_offset = SONYPI_TYPE2_OFFSET,
+               .event_types = type2_events,
+       },
+       {
+               .model = SONYPI_DEVICE_TYPE3,
+               .handle_irq = NULL,
+               .evport_offset = SONYPI_TYPE3_OFFSET,
+               .event_types = type3_events,
+       },
+       {
+               .model = SONYPI_DEVICE_TYPE4,
+               .handle_irq = type4_handle_irq,
+               .evport_offset = SONYPI_TYPE4_OFFSET,
+               .event_types = type4_events,
+       },
+};
+
+static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
+{
+       struct pci_dev *pcidev;
+
+       pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+       if (pcidev) {
+               dev->control = &spic_types[0];
+               goto out;
+       }
+
+       pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
+       if (pcidev) {
+               dev->control = &spic_types[2];
+               goto out;
+       }
+
+       pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
+       if (pcidev) {
+               dev->control = &spic_types[3];
+               goto out;
+       }
+
+       pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
+       if (pcidev) {
+               dev->control = &spic_types[3];
+               goto out;
+       }
+
+       /* default */
+       dev->control = &spic_types[1];
+
+out:
+       if (pcidev)
+               pci_dev_put(pcidev);
+
+       printk(KERN_INFO DRV_PFX "detected Type%d model\n",
+                       dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 :
+                       dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 :
+                       dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4);
+}
+
 /* camera tests and poweron/poweroff */
 #define SONYPI_CAMERA_PICTURE          5
 #define SONYPI_CAMERA_CONTROL          0x10
@@ -2253,7 +2362,7 @@ static int sony_pic_enable(struct acpi_device *device,
        buffer.pointer = resource;
 
        /* setup Type 1 resources */
-       if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
+       if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) {
 
                /* setup io resources */
                resource->res1.type = ACPI_RESOURCE_TYPE_IO;
@@ -2335,39 +2444,49 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
        if (dev->cur_ioport->io2.minimum)
                data_mask = inb_p(dev->cur_ioport->io2.minimum);
        else
-               data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset);
+               data_mask = inb_p(dev->cur_ioport->io1.minimum +
+                               dev->control->evport_offset);
 
        dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
-                       ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset);
+                       ev, data_mask, dev->cur_ioport->io1.minimum,
+                       dev->control->evport_offset);
 
        if (ev == 0x00 || ev == 0xff)
                return IRQ_HANDLED;
 
-       for (i = 0; sony_pic_eventtypes[i].model; i++) {
-
-               if (spic_dev.model != sony_pic_eventtypes[i].model)
-                       continue;
+       for (i = 0; dev->control->event_types[i].mask; i++) {
 
-               if ((data_mask & sony_pic_eventtypes[i].data) !=
-                   sony_pic_eventtypes[i].data)
+               if ((data_mask & dev->control->event_types[i].data) !=
+                   dev->control->event_types[i].data)
                        continue;
 
-               if (!(mask & sony_pic_eventtypes[i].mask))
+               if (!(mask & dev->control->event_types[i].mask))
                        continue;
 
-               for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {
-                       if (ev == sony_pic_eventtypes[i].events[j].data) {
+               for (j = 0; dev->control->event_types[i].events[j].event; j++) {
+                       if (ev == dev->control->event_types[i].events[j].data) {
                                device_event =
-                                       sony_pic_eventtypes[i].events[j].event;
+                                       dev->control->
+                                               event_types[i].events[j].event;
                                goto found;
                        }
                }
        }
+       /* Still not able to decode the event try to pass
+        * it over to the minidriver
+        */
+       if (dev->control->handle_irq &&
+                       dev->control->handle_irq(data_mask, ev) == 0)
+               return IRQ_HANDLED;
+
+       dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
+                       ev, data_mask, dev->cur_ioport->io1.minimum,
+                       dev->control->evport_offset);
        return IRQ_HANDLED;
 
 found:
        sony_laptop_report_input_event(device_event);
-       acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event);
+       acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
        sonypi_compat_report_event(device_event);
 
        return IRQ_HANDLED;
@@ -2429,23 +2548,9 @@ static int sony_pic_add(struct acpi_device *device)
 
        spic_dev.acpi_dev = device;
        strcpy(acpi_device_class(device), "sony/hotkey");
-       spic_dev.model = sony_pic_detect_device_type();
+       sony_pic_detect_device_type(&spic_dev);
        mutex_init(&spic_dev.lock);
 
-       /* model specific characteristics */
-       switch(spic_dev.model) {
-               case SONYPI_DEVICE_TYPE1:
-                       spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
-                       break;
-               case SONYPI_DEVICE_TYPE3:
-                       spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
-                       break;
-               case SONYPI_DEVICE_TYPE2:
-               default:
-                       spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
-                       break;
-       }
-
        /* read _PRS resources */
        result = sony_pic_possible_resources(device);
        if (result) {
diff --git a/drivers/misc/tc1100-wmi.c b/drivers/misc/tc1100-wmi.c
new file mode 100644 (file)
index 0000000..f25e4c9
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ *  HP Compaq TC1100 Tablet WMI Extras Driver
+ *
+ *  Copyright (C) 2007 Carlos Corbacho <carlos@strangeworlds.co.uk>
+ *  Copyright (C) 2004 Jamey Hicks <jamey.hicks@hp.com>
+ *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <acpi/acpi.h>
+#include <acpi/actypes.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/platform_device.h>
+
+#define GUID "C364AC71-36DB-495A-8494-B439D472A505"
+
+#define TC1100_INSTANCE_WIRELESS               1
+#define TC1100_INSTANCE_JOGDIAL                2
+
+#define TC1100_LOGPREFIX "tc1100-wmi: "
+#define TC1100_INFO KERN_INFO TC1100_LOGPREFIX
+
+MODULE_AUTHOR("Jamey Hicks, Carlos Corbacho");
+MODULE_DESCRIPTION("HP Compaq TC1100 Tablet WMI Extras");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505");
+
+static int tc1100_probe(struct platform_device *device);
+static int tc1100_remove(struct platform_device *device);
+static int tc1100_suspend(struct platform_device *device, pm_message_t state);
+static int tc1100_resume(struct platform_device *device);
+
+static struct platform_driver tc1100_driver = {
+       .driver = {
+               .name = "tc1100-wmi",
+               .owner = THIS_MODULE,
+       },
+       .probe = tc1100_probe,
+       .remove = tc1100_remove,
+       .suspend = tc1100_suspend,
+       .resume = tc1100_resume,
+};
+
+static struct platform_device *tc1100_device;
+
+struct tc1100_data {
+       u32 wireless;
+       u32 jogdial;
+};
+
+static struct tc1100_data suspend_data;
+
+/* --------------------------------------------------------------------------
+                               Device Management
+   -------------------------------------------------------------------------- */
+
+static int get_state(u32 *out, u8 instance)
+{
+       u32 tmp;
+       acpi_status status;
+       struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+
+       if (!out)
+               return -EINVAL;
+
+       if (instance > 2)
+               return -ENODEV;
+
+       status = wmi_query_block(GUID, instance, &result);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       obj = (union acpi_object *) result.pointer;
+       if (obj && obj->type == ACPI_TYPE_BUFFER &&
+               obj->buffer.length == sizeof(u32)) {
+               tmp = *((u32 *) obj->buffer.pointer);
+       } else {
+               tmp = 0;
+       }
+
+       if (result.length > 0 && result.pointer)
+               kfree(result.pointer);
+
+       switch (instance) {
+       case TC1100_INSTANCE_WIRELESS:
+               *out = (tmp == 3) ? 1 : 0;
+               return 0;
+       case TC1100_INSTANCE_JOGDIAL:
+               *out = (tmp == 1) ? 1 : 0;
+               return 0;
+       default:
+               return -ENODEV;
+       }
+}
+
+static int set_state(u32 *in, u8 instance)
+{
+       u32 value;
+       acpi_status status;
+       struct acpi_buffer input;
+
+       if (!in)
+               return -EINVAL;
+
+       if (instance > 2)
+               return -ENODEV;
+
+       switch (instance) {
+       case TC1100_INSTANCE_WIRELESS:
+               value = (*in) ? 1 : 2;
+               break;
+       case TC1100_INSTANCE_JOGDIAL:
+               value = (*in) ? 0 : 1;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       input.length = sizeof(u32);
+       input.pointer = &value;
+
+       status = wmi_set_block(GUID, instance, &input);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       return 0;
+}
+
+/* --------------------------------------------------------------------------
+                               FS Interface (/sys)
+   -------------------------------------------------------------------------- */
+
+/*
+ * Read/ write bool sysfs macro
+ */
+#define show_set_bool(value, instance) \
+static ssize_t \
+show_bool_##value(struct device *dev, struct device_attribute *attr, \
+       char *buf) \
+{ \
+       u32 result; \
+       acpi_status status = get_state(&result, instance); \
+       if (ACPI_SUCCESS(status)) \
+               return sprintf(buf, "%d\n", result); \
+       return sprintf(buf, "Read error\n"); \
+} \
+\
+static ssize_t \
+set_bool_##value(struct device *dev, struct device_attribute *attr, \
+       const char *buf, size_t count) \
+{ \
+       u32 tmp = simple_strtoul(buf, NULL, 10); \
+       acpi_status status = set_state(&tmp, instance); \
+               if (ACPI_FAILURE(status)) \
+                       return -EINVAL; \
+       return count; \
+} \
+static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
+       show_bool_##value, set_bool_##value);
+
+show_set_bool(wireless, TC1100_INSTANCE_WIRELESS);
+show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL);
+
+static void remove_fs(void)
+{
+       device_remove_file(&tc1100_device->dev, &dev_attr_wireless);
+       device_remove_file(&tc1100_device->dev, &dev_attr_jogdial);
+}
+
+static int add_fs(void)
+{
+       int ret;
+
+       ret = device_create_file(&tc1100_device->dev, &dev_attr_wireless);
+       if (ret)
+               goto add_sysfs_error;
+
+       ret = device_create_file(&tc1100_device->dev, &dev_attr_jogdial);
+       if (ret)
+               goto add_sysfs_error;
+
+       return ret;
+
+add_sysfs_error:
+       remove_fs();
+       return ret;
+}
+
+/* --------------------------------------------------------------------------
+                               Driver Model
+   -------------------------------------------------------------------------- */
+
+static int tc1100_probe(struct platform_device *device)
+{
+       int result = 0;
+
+       result = add_fs();
+       return result;
+}
+
+
+static int tc1100_remove(struct platform_device *device)
+{
+       remove_fs();
+       return 0;
+}
+
+static int tc1100_suspend(struct platform_device *dev, pm_message_t state)
+{
+       int ret;
+
+       ret = get_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS);
+       if (ret)
+               return ret;
+
+       ret = get_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static int tc1100_resume(struct platform_device *dev)
+{
+       int ret;
+
+       ret = set_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS);
+       if (ret)
+               return ret;
+
+       ret = set_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static int __init tc1100_init(void)
+{
+       int result = 0;
+
+       if (!wmi_has_guid(GUID))
+               return -ENODEV;
+
+       result = platform_driver_register(&tc1100_driver);
+       if (result)
+               return result;
+
+       tc1100_device = platform_device_alloc("tc1100-wmi", -1);
+       platform_device_add(tc1100_device);
+
+       printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n");
+
+       return result;
+}
+
+static void __exit tc1100_exit(void)
+{
+       platform_device_del(tc1100_device);
+       platform_driver_unregister(&tc1100_driver);
+
+       printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras unloaded\n");
+}
+
+module_init(tc1100_init);
+module_exit(tc1100_exit);
index cf56647a6ca4822307d52b5911b4a4152b7a7766..7ba1acad54025d1fd3cccf9ec9756345fe6bb27c 100644 (file)
@@ -3,7 +3,7 @@
  *
  *
  *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
- *  Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ *  Copyright (C) 2006-2008 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
  *
  *  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
  *  02110-1301, USA.
  */
 
-#define IBM_VERSION "0.17"
-#define TPACPI_SYSFS_VERSION 0x020000
+#define TPACPI_VERSION "0.19"
+#define TPACPI_SYSFS_VERSION 0x020200
 
 /*
  *  Changelog:
+ *  2007-10-20         changelog trimmed down
+ *
  *  2007-03-27  0.14   renamed to thinkpad_acpi and moved to
  *                     drivers/misc.
  *
  *                     changelog now lives in git commit history, and will
  *                     not be updated further in-file.
  *
- *  2005-08-17  0.12   fix compilation on 2.6.13-rc kernels
  *  2005-03-17 0.11    support for 600e, 770x
  *                         thanks to Jamie Lentin <lentinj@dial.pipex.com>
- *                     support for 770e, G41
- *                     G40 and G41 don't have a thinklight
- *                     temperatures no longer experimental
- *                     experimental brightness control
- *                     experimental volume control
- *                     experimental fan enable/disable
- *  2005-01-16 0.10    fix module loading on R30, R31
- *  2005-01-16 0.9     support for 570, R30, R31
- *                     ultrabay support on A22p, A3x
- *                     limit arg for cmos, led, beep, drop experimental status
- *                     more capable led control on A21e, A22p, T20-22, X20
- *                     experimental temperatures and fan speed
- *                     experimental embedded controller register dump
- *                     mark more functions as __init, drop incorrect __exit
- *                     use MODULE_VERSION
+ *
+ *  2005-01-16 0.9     use MODULE_VERSION
  *                         thanks to Henrik Brix Andersen <brix@gentoo.org>
  *                     fix parameter passing on module loading
  *                         thanks to Rusty Russell <rusty@rustcorp.com.au>
  *                         thanks to Jim Radford <radford@blackbean.org>
  *  2004-11-08 0.8     fix init error case, don't return from a macro
  *                         thanks to Chris Wright <chrisw@osdl.org>
- *  2004-10-23 0.7     fix module loading on A21e, A22p, T20, T21, X20
- *                     fix led control on A21e
- *  2004-10-19 0.6     use acpi_bus_register_driver() to claim HKEY device
- *  2004-10-18 0.5     thinklight support on A21e, G40, R32, T20, T21, X20
- *                     proc file format changed
- *                     video_switch command
- *                     experimental cmos control
- *                     experimental led control
- *                     experimental acpi sounds
- *  2004-09-16 0.4     support for module parameters
- *                     hotkey mask can be prefixed by 0x
- *                     video output switching
- *                     video expansion control
- *                     ultrabay eject support
- *                     removed lcd brightness/on/off control, didn't work
- *  2004-08-17 0.3     support for R40
- *                     lcd off, brightness control
- *                     thinklight on/off
- *  2004-08-14 0.2     support for T series, X20
- *                     bluetooth enable/disable
- *                     hotkey events disabled by default
- *                     removed fan control, currently useless
- *  2004-08-09 0.1     initial release, support for X series
  */
 
-#include "thinkpad_acpi.h"
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/delay.h>
+
+#include <linux/nvram.h>
+#include <linux/proc_fs.h>
+#include <linux/sysfs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/input.h>
+#include <asm/uaccess.h>
+
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+
+#include <acpi/acpi_drivers.h>
+#include <acpi/acnamesp.h>
+
+#include <linux/pci_ids.h>
+
+
+/* ThinkPad CMOS commands */
+#define TP_CMOS_VOLUME_DOWN    0
+#define TP_CMOS_VOLUME_UP      1
+#define TP_CMOS_VOLUME_MUTE    2
+#define TP_CMOS_BRIGHTNESS_UP  4
+#define TP_CMOS_BRIGHTNESS_DOWN        5
+
+/* NVRAM Addresses */
+enum tp_nvram_addr {
+       TP_NVRAM_ADDR_HK2               = 0x57,
+       TP_NVRAM_ADDR_THINKLIGHT        = 0x58,
+       TP_NVRAM_ADDR_VIDEO             = 0x59,
+       TP_NVRAM_ADDR_BRIGHTNESS        = 0x5e,
+       TP_NVRAM_ADDR_MIXER             = 0x60,
+};
 
-MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
-MODULE_DESCRIPTION(IBM_DESC);
-MODULE_VERSION(IBM_VERSION);
-MODULE_LICENSE("GPL");
+/* NVRAM bit masks */
+enum {
+       TP_NVRAM_MASK_HKT_THINKPAD      = 0x08,
+       TP_NVRAM_MASK_HKT_ZOOM          = 0x20,
+       TP_NVRAM_MASK_HKT_DISPLAY       = 0x40,
+       TP_NVRAM_MASK_HKT_HIBERNATE     = 0x80,
+       TP_NVRAM_MASK_THINKLIGHT        = 0x10,
+       TP_NVRAM_MASK_HKT_DISPEXPND     = 0x30,
+       TP_NVRAM_MASK_HKT_BRIGHTNESS    = 0x20,
+       TP_NVRAM_MASK_LEVEL_BRIGHTNESS  = 0x0f,
+       TP_NVRAM_POS_LEVEL_BRIGHTNESS   = 0,
+       TP_NVRAM_MASK_MUTE              = 0x40,
+       TP_NVRAM_MASK_HKT_VOLUME        = 0x80,
+       TP_NVRAM_MASK_LEVEL_VOLUME      = 0x0f,
+       TP_NVRAM_POS_LEVEL_VOLUME       = 0,
+};
 
-/* Please remove this in year 2009 */
-MODULE_ALIAS("ibm_acpi");
+/* ACPI HIDs */
+#define TPACPI_ACPI_HKEY_HID           "IBM0068"
 
-/*
- * DMI matching for module autoloading
- *
- * See http://thinkwiki.org/wiki/List_of_DMI_IDs
- * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
- *
- * Only models listed in thinkwiki will be supported, so add yours
- * if it is not there yet.
+/* Input IDs */
+#define TPACPI_HKEY_INPUT_PRODUCT      0x5054 /* "TP" */
+#define TPACPI_HKEY_INPUT_VERSION      0x4101
+
+
+/****************************************************************************
+ * Main driver
  */
-#define IBM_BIOS_MODULE_ALIAS(__type) \
-       MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
 
-/* Non-ancient thinkpads */
-MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
-MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
+#define TPACPI_NAME "thinkpad"
+#define TPACPI_DESC "ThinkPad ACPI Extras"
+#define TPACPI_FILE TPACPI_NAME "_acpi"
+#define TPACPI_URL "http://ibm-acpi.sf.net/"
+#define TPACPI_MAIL "ibm-acpi-devel@lists.sourceforge.net"
+
+#define TPACPI_PROC_DIR "ibm"
+#define TPACPI_ACPI_EVENT_PREFIX "ibm"
+#define TPACPI_DRVR_NAME TPACPI_FILE
+#define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon"
+
+#define TPACPI_MAX_ACPI_ARGS 3
+
+/* Debugging */
+#define TPACPI_LOG TPACPI_FILE ": "
+#define TPACPI_ERR        KERN_ERR    TPACPI_LOG
+#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG
+#define TPACPI_INFO   KERN_INFO   TPACPI_LOG
+#define TPACPI_DEBUG  KERN_DEBUG  TPACPI_LOG
+
+#define TPACPI_DBG_ALL         0xffff
+#define TPACPI_DBG_ALL         0xffff
+#define TPACPI_DBG_INIT                0x0001
+#define TPACPI_DBG_EXIT                0x0002
+#define dbg_printk(a_dbg_level, format, arg...) \
+       do { if (dbg_level & a_dbg_level) \
+               printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \
+       } while (0)
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+#define vdbg_printk(a_dbg_level, format, arg...) \
+       dbg_printk(a_dbg_level, format, ## arg)
+static const char *str_supported(int is_supported);
+#else
+#define vdbg_printk(a_dbg_level, format, arg...)
+#endif
 
-/* Ancient thinkpad BIOSes have to be identified by
- * BIOS type or model number, and there are far less
- * BIOS types than model numbers... */
-IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
-IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
-IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
+#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off")
+#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
+#define strlencmp(a, b) (strncmp((a), (b), strlen(b)))
 
-#define __unused __attribute__ ((unused))
+
+/****************************************************************************
+ * Driver-wide structs and misc. variables
+ */
+
+struct ibm_struct;
+
+struct tp_acpi_drv_struct {
+       const struct acpi_device_id *hid;
+       struct acpi_driver *driver;
+
+       void (*notify) (struct ibm_struct *, u32);
+       acpi_handle *handle;
+       u32 type;
+       struct acpi_device *device;
+};
+
+struct ibm_struct {
+       char *name;
+
+       int (*read) (char *);
+       int (*write) (char *);
+       void (*exit) (void);
+       void (*resume) (void);
+       void (*suspend) (pm_message_t state);
+
+       struct list_head all_drivers;
+
+       struct tp_acpi_drv_struct *acpi;
+
+       struct {
+               u8 acpi_driver_registered:1;
+               u8 acpi_notify_installed:1;
+               u8 proc_created:1;
+               u8 init_called:1;
+               u8 experimental:1;
+       } flags;
+};
+
+struct ibm_init_struct {
+       char param[32];
+
+       int (*init) (struct ibm_init_struct *);
+       struct ibm_struct *data;
+};
+
+static struct {
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+       u32 bay_status:1;
+       u32 bay_eject:1;
+       u32 bay_status2:1;
+       u32 bay_eject2:1;
+#endif
+       u32 bluetooth:1;
+       u32 hotkey:1;
+       u32 hotkey_mask:1;
+       u32 hotkey_wlsw:1;
+       u32 light:1;
+       u32 light_status:1;
+       u32 bright_16levels:1;
+       u32 wan:1;
+       u32 fan_ctrl_status_undef:1;
+       u32 input_device_registered:1;
+       u32 platform_drv_registered:1;
+       u32 platform_drv_attrs_registered:1;
+       u32 sensors_pdrv_registered:1;
+       u32 sensors_pdrv_attrs_registered:1;
+       u32 sensors_pdev_attrs_registered:1;
+       u32 hotkey_poll_active:1;
+} tp_features;
+
+struct thinkpad_id_data {
+       unsigned int vendor;    /* ThinkPad vendor:
+                                * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
+
+       char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
+       char *ec_version_str;   /* Something like 1ZHT51WW-1.04a */
+
+       u16 bios_model;         /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
+       u16 ec_model;
+
+       char *model_str;
+};
+static struct thinkpad_id_data thinkpad_id;
 
 static enum {
        TPACPI_LIFE_INIT = 0,
@@ -123,6 +255,9 @@ static enum {
        TPACPI_LIFE_EXITING,
 } tpacpi_lifecycle;
 
+static int experimental;
+static u32 dbg_level;
+
 /****************************************************************************
  ****************************************************************************
  *
@@ -137,13 +272,13 @@ static enum {
 
 static acpi_handle root_handle;
 
-#define IBM_HANDLE(object, parent, paths...)                   \
+#define TPACPI_HANDLE(object, parent, paths...)                        \
        static acpi_handle  object##_handle;                    \
        static acpi_handle *object##_parent = &parent##_handle; \
        static char        *object##_path;                      \
        static char        *object##_paths[] = { paths }
 
-IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",     /* 240, 240x */
+TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",  /* 240, 240x */
           "\\_SB.PCI.ISA.EC",  /* 570 */
           "\\_SB.PCI0.ISA0.EC0",       /* 600e/x, 770e, 770x */
           "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
@@ -152,20 +287,16 @@ IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",        /* 240, 240x */
           "\\_SB.PCI0.LPC.EC", /* all others */
           );
 
-IBM_HANDLE(ecrd, ec, "ECRD");  /* 570 */
-IBM_HANDLE(ecwr, ec, "ECWR");  /* 570 */
-
+TPACPI_HANDLE(ecrd, ec, "ECRD");       /* 570 */
+TPACPI_HANDLE(ecwr, ec, "ECWR");       /* 570 */
 
-/*************************************************************************
- * Misc ACPI handles
- */
-
-IBM_HANDLE(cmos, root, "\\UCMS",       /* R50, R50e, R50p, R51, T4x, X31, X40 */
+TPACPI_HANDLE(cmos, root, "\\UCMS",    /* R50, R50e, R50p, R51, */
+                                       /* T4x, X31, X40 */
           "\\CMOS",            /* A3x, G4x, R32, T23, T30, X22-24, X30 */
           "\\CMS",             /* R40, R40e */
           );                   /* all others */
 
-IBM_HANDLE(hkey, ec, "\\_SB.HKEY",     /* 600e/x, 770e, 770x */
+TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY",  /* 600e/x, 770e, 770x */
           "^HKEY",             /* R30, R31 */
           "HKEY",              /* all others */
           );                   /* 570 */
@@ -180,7 +311,7 @@ static int acpi_evalf(acpi_handle handle,
 {
        char *fmt0 = fmt;
        struct acpi_object_list params;
-       union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
+       union acpi_object in_objs[TPACPI_MAX_ACPI_ARGS];
        struct acpi_buffer result, *resultp;
        union acpi_object out_obj;
        acpi_status status;
@@ -190,7 +321,7 @@ static int acpi_evalf(acpi_handle handle,
        int quiet;
 
        if (!*fmt) {
-               printk(IBM_ERR "acpi_evalf() called with empty format\n");
+               printk(TPACPI_ERR "acpi_evalf() called with empty format\n");
                return 0;
        }
 
@@ -215,7 +346,7 @@ static int acpi_evalf(acpi_handle handle,
                        break;
                        /* add more types as needed */
                default:
-                       printk(IBM_ERR "acpi_evalf() called "
+                       printk(TPACPI_ERR "acpi_evalf() called "
                               "with invalid format character '%c'\n", c);
                        return 0;
                }
@@ -242,29 +373,19 @@ static int acpi_evalf(acpi_handle handle,
                break;
                /* add more types as needed */
        default:
-               printk(IBM_ERR "acpi_evalf() called "
+               printk(TPACPI_ERR "acpi_evalf() called "
                       "with invalid format character '%c'\n", res_type);
                return 0;
        }
 
        if (!success && !quiet)
-               printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
+               printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
                       method, fmt0, status);
 
        return success;
 }
 
-static void __unused acpi_print_int(acpi_handle handle, char *method)
-{
-       int i;
-
-       if (acpi_evalf(handle, &i, method, "d"))
-               printk(IBM_INFO "%s = 0x%x\n", method, i);
-       else
-               printk(IBM_ERR "error calling %s\n", method);
-}
-
-static int acpi_ec_read(int i, u8 * p)
+static int acpi_ec_read(int i, u8 *p)
 {
        int v;
 
@@ -293,6 +414,7 @@ static int acpi_ec_write(int i, u8 v)
        return 1;
 }
 
+#if defined(CONFIG_THINKPAD_ACPI_DOCK) || defined(CONFIG_THINKPAD_ACPI_BAY)
 static int _sta(acpi_handle handle)
 {
        int status;
@@ -302,6 +424,7 @@ static int _sta(acpi_handle handle)
 
        return status;
 }
+#endif
 
 static int issue_thinkpad_cmos_command(int cmos_cmd)
 {
@@ -318,6 +441,10 @@ static int issue_thinkpad_cmos_command(int cmos_cmd)
  * ACPI device model
  */
 
+#define TPACPI_ACPIHANDLE_INIT(object) \
+       drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
+               object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
+
 static void drv_acpi_handle_init(char *name,
                           acpi_handle *handle, acpi_handle parent,
                           char **paths, int num_paths, char **path)
@@ -372,25 +499,27 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
 
        rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
        if (rc < 0) {
-               printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n",
+               printk(TPACPI_ERR "acpi_bus_get_device(%s) failed: %d\n",
                        ibm->name, rc);
                return -ENODEV;
        }
 
        acpi_driver_data(ibm->acpi->device) = ibm;
        sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
-               IBM_ACPI_EVENT_PREFIX,
+               TPACPI_ACPI_EVENT_PREFIX,
                ibm->name);
 
        status = acpi_install_notify_handler(*ibm->acpi->handle,
                        ibm->acpi->type, dispatch_acpi_notify, ibm);
        if (ACPI_FAILURE(status)) {
                if (status == AE_ALREADY_EXISTS) {
-                       printk(IBM_NOTICE "another device driver is already handling %s events\n",
-                               ibm->name);
+                       printk(TPACPI_NOTICE
+                              "another device driver is already "
+                              "handling %s events\n", ibm->name);
                } else {
-                       printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
-                               ibm->name, status);
+                       printk(TPACPI_ERR
+                              "acpi_install_notify_handler(%s) failed: %d\n",
+                              ibm->name, status);
                }
                return -ENODEV;
        }
@@ -414,18 +543,18 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
 
        ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
        if (!ibm->acpi->driver) {
-               printk(IBM_ERR "kzalloc(ibm->driver) failed\n");
+               printk(TPACPI_ERR "kzalloc(ibm->driver) failed\n");
                return -ENOMEM;
        }
 
-       sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
+       sprintf(ibm->acpi->driver->name, "%s_%s", TPACPI_NAME, ibm->name);
        ibm->acpi->driver->ids = ibm->acpi->hid;
 
        ibm->acpi->driver->ops.add = &tpacpi_device_add;
 
        rc = acpi_bus_register_driver(ibm->acpi->driver);
        if (rc < 0) {
-               printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
+               printk(TPACPI_ERR "acpi_bus_register_driver(%s) failed: %d\n",
                       ibm->name, rc);
                kfree(ibm->acpi->driver);
                ibm->acpi->driver = NULL;
@@ -470,7 +599,7 @@ static int dispatch_procfs_read(char *page, char **start, off_t off,
 }
 
 static int dispatch_procfs_write(struct file *file,
-                       const char __user * userbuf,
+                       const char __user *userbuf,
                        unsigned long count, void *data)
 {
        struct ibm_struct *ibm = data;
@@ -530,7 +659,22 @@ static struct platform_device *tpacpi_sensors_pdev;
 static struct device *tpacpi_hwmon;
 static struct input_dev *tpacpi_inputdev;
 static struct mutex tpacpi_inputdev_send_mutex;
+static LIST_HEAD(tpacpi_all_drivers);
+
+static int tpacpi_suspend_handler(struct platform_device *pdev,
+                                 pm_message_t state)
+{
+       struct ibm_struct *ibm, *itmp;
+
+       list_for_each_entry_safe(ibm, itmp,
+                                &tpacpi_all_drivers,
+                                all_drivers) {
+               if (ibm->suspend)
+                       (ibm->suspend)(state);
+       }
 
+       return 0;
+}
 
 static int tpacpi_resume_handler(struct platform_device *pdev)
 {
@@ -548,107 +692,36 @@ static int tpacpi_resume_handler(struct platform_device *pdev)
 
 static struct platform_driver tpacpi_pdriver = {
        .driver = {
-               .name = IBM_DRVR_NAME,
+               .name = TPACPI_DRVR_NAME,
                .owner = THIS_MODULE,
        },
+       .suspend = tpacpi_suspend_handler,
        .resume = tpacpi_resume_handler,
 };
 
 static struct platform_driver tpacpi_hwmon_pdriver = {
        .driver = {
-               .name = IBM_HWMON_DRVR_NAME,
+               .name = TPACPI_HWMON_DRVR_NAME,
                .owner = THIS_MODULE,
        },
 };
 
 /*************************************************************************
- * thinkpad-acpi driver attributes
+ * sysfs support helpers
  */
 
-/* interface_version --------------------------------------------------- */
-static ssize_t tpacpi_driver_interface_version_show(
-                               struct device_driver *drv,
-                               char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
-}
-
-static DRIVER_ATTR(interface_version, S_IRUGO,
-               tpacpi_driver_interface_version_show, NULL);
-
-/* debug_level --------------------------------------------------------- */
-static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
-                                               char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
-}
-
-static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
-                                               const char *buf, size_t count)
-{
-       unsigned long t;
-
-       if (parse_strtoul(buf, 0xffff, &t))
-               return -EINVAL;
-
-       dbg_level = t;
-
-       return count;
-}
-
-static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
-               tpacpi_driver_debug_show, tpacpi_driver_debug_store);
-
-/* version ------------------------------------------------------------- */
-static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
-                                               char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
-}
-
-static DRIVER_ATTR(version, S_IRUGO,
-               tpacpi_driver_version_show, NULL);
-
-/* --------------------------------------------------------------------- */
-
-static struct driver_attribute* tpacpi_driver_attributes[] = {
-       &driver_attr_debug_level, &driver_attr_version,
-       &driver_attr_interface_version,
+struct attribute_set {
+       unsigned int members, max_members;
+       struct attribute_group group;
 };
 
-static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
-{
-       int i, res;
-
-       i = 0;
-       res = 0;
-       while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
-               res = driver_create_file(drv, tpacpi_driver_attributes[i]);
-               i++;
-       }
-
-       return res;
-}
-
-static void tpacpi_remove_driver_attributes(struct device_driver *drv)
-{
-       int i;
-
-       for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
-               driver_remove_file(drv, tpacpi_driver_attributes[i]);
-}
-
-/*************************************************************************
- * sysfs support helpers
- */
-
 struct attribute_set_obj {
        struct attribute_set s;
        struct attribute *a;
 } __attribute__((packed));
 
 static struct attribute_set *create_attr_set(unsigned int max_members,
-                                               const charname)
+                                               const char *name)
 {
        struct attribute_set_obj *sobj;
 
@@ -668,8 +741,11 @@ static struct attribute_set *create_attr_set(unsigned int max_members,
        return &sobj->s;
 }
 
+#define destroy_attr_set(_set) \
+       kfree(_set);
+
 /* not multi-threaded safe, use it in a single thread per set */
-static int add_to_attr_set(struct attribute_sets, struct attribute *attr)
+static int add_to_attr_set(struct attribute_set *s, struct attribute *attr)
 {
        if (!s || !attr)
                return -EINVAL;
@@ -683,7 +759,7 @@ static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
        return 0;
 }
 
-static int add_many_to_attr_set(struct attribute_sets,
+static int add_many_to_attr_set(struct attribute_set *s,
                        struct attribute **attr,
                        unsigned int count)
 {
@@ -698,12 +774,15 @@ static int add_many_to_attr_set(struct attribute_set* s,
        return 0;
 }
 
-static void delete_attr_set(struct attribute_sets, struct kobject *kobj)
+static void delete_attr_set(struct attribute_set *s, struct kobject *kobj)
 {
        sysfs_remove_group(kobj, &s->group);
        destroy_attr_set(s);
 }
 
+#define register_attr_set_with_sysfs(_attr_set, _kobj) \
+       sysfs_create_group(_kobj, &_attr_set->group)
+
 static int parse_strtoul(const char *buf,
                unsigned long max, unsigned long *value)
 {
@@ -720,6 +799,84 @@ static int parse_strtoul(const char *buf,
        return 0;
 }
 
+/*************************************************************************
+ * thinkpad-acpi driver attributes
+ */
+
+/* interface_version --------------------------------------------------- */
+static ssize_t tpacpi_driver_interface_version_show(
+                               struct device_driver *drv,
+                               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
+}
+
+static DRIVER_ATTR(interface_version, S_IRUGO,
+               tpacpi_driver_interface_version_show, NULL);
+
+/* debug_level --------------------------------------------------------- */
+static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
+                                               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
+}
+
+static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
+                                               const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 0xffff, &t))
+               return -EINVAL;
+
+       dbg_level = t;
+
+       return count;
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+               tpacpi_driver_debug_show, tpacpi_driver_debug_store);
+
+/* version ------------------------------------------------------------- */
+static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
+                                               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s v%s\n",
+                       TPACPI_DESC, TPACPI_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO,
+               tpacpi_driver_version_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
+static struct driver_attribute *tpacpi_driver_attributes[] = {
+       &driver_attr_debug_level, &driver_attr_version,
+       &driver_attr_interface_version,
+};
+
+static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
+{
+       int i, res;
+
+       i = 0;
+       res = 0;
+       while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
+               res = driver_create_file(drv, tpacpi_driver_attributes[i]);
+               i++;
+       }
+
+       return res;
+}
+
+static void tpacpi_remove_driver_attributes(struct device_driver *drv)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
+               driver_remove_file(drv, tpacpi_driver_attributes[i]);
+}
+
 /****************************************************************************
  ****************************************************************************
  *
@@ -734,17 +891,17 @@ static int parse_strtoul(const char *buf,
 
 static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
 {
-       printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
-       printk(IBM_INFO "%s\n", IBM_URL);
+       printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION);
+       printk(TPACPI_INFO "%s\n", TPACPI_URL);
 
-       printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
+       printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n",
                (thinkpad_id.bios_version_str) ?
                        thinkpad_id.bios_version_str : "unknown",
                (thinkpad_id.ec_version_str) ?
                        thinkpad_id.ec_version_str : "unknown");
 
        if (thinkpad_id.vendor && thinkpad_id.model_str)
-               printk(IBM_INFO "%s %s\n",
+               printk(TPACPI_INFO "%s %s\n",
                        (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
                                "IBM" : ((thinkpad_id.vendor ==
                                                PCI_VENDOR_ID_LENOVO) ?
@@ -758,8 +915,8 @@ static int thinkpad_acpi_driver_read(char *p)
 {
        int len = 0;
 
-       len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
-       len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
+       len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC);
+       len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION);
 
        return len;
 }
@@ -773,15 +930,129 @@ static struct ibm_struct thinkpad_acpi_driver_data = {
  * Hotkey subdriver
  */
 
+enum { /* hot key scan codes (derived from ACPI DSDT) */
+       TP_ACPI_HOTKEYSCAN_FNF1         = 0,
+       TP_ACPI_HOTKEYSCAN_FNF2,
+       TP_ACPI_HOTKEYSCAN_FNF3,
+       TP_ACPI_HOTKEYSCAN_FNF4,
+       TP_ACPI_HOTKEYSCAN_FNF5,
+       TP_ACPI_HOTKEYSCAN_FNF6,
+       TP_ACPI_HOTKEYSCAN_FNF7,
+       TP_ACPI_HOTKEYSCAN_FNF8,
+       TP_ACPI_HOTKEYSCAN_FNF9,
+       TP_ACPI_HOTKEYSCAN_FNF10,
+       TP_ACPI_HOTKEYSCAN_FNF11,
+       TP_ACPI_HOTKEYSCAN_FNF12,
+       TP_ACPI_HOTKEYSCAN_FNBACKSPACE,
+       TP_ACPI_HOTKEYSCAN_FNINSERT,
+       TP_ACPI_HOTKEYSCAN_FNDELETE,
+       TP_ACPI_HOTKEYSCAN_FNHOME,
+       TP_ACPI_HOTKEYSCAN_FNEND,
+       TP_ACPI_HOTKEYSCAN_FNPAGEUP,
+       TP_ACPI_HOTKEYSCAN_FNPAGEDOWN,
+       TP_ACPI_HOTKEYSCAN_FNSPACE,
+       TP_ACPI_HOTKEYSCAN_VOLUMEUP,
+       TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
+       TP_ACPI_HOTKEYSCAN_MUTE,
+       TP_ACPI_HOTKEYSCAN_THINKPAD,
+};
+
+enum { /* Keys available through NVRAM polling */
+       TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U,
+       TPACPI_HKEY_NVRAM_GOOD_MASK  = 0x00fb8000U,
+};
+
+enum { /* Positions of some of the keys in hotkey masks */
+       TP_ACPI_HKEY_DISPSWTCH_MASK     = 1 << TP_ACPI_HOTKEYSCAN_FNF7,
+       TP_ACPI_HKEY_DISPXPAND_MASK     = 1 << TP_ACPI_HOTKEYSCAN_FNF8,
+       TP_ACPI_HKEY_HIBERNATE_MASK     = 1 << TP_ACPI_HOTKEYSCAN_FNF12,
+       TP_ACPI_HKEY_BRGHTUP_MASK       = 1 << TP_ACPI_HOTKEYSCAN_FNHOME,
+       TP_ACPI_HKEY_BRGHTDWN_MASK      = 1 << TP_ACPI_HOTKEYSCAN_FNEND,
+       TP_ACPI_HKEY_THNKLGHT_MASK      = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP,
+       TP_ACPI_HKEY_ZOOM_MASK          = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE,
+       TP_ACPI_HKEY_VOLUP_MASK         = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP,
+       TP_ACPI_HKEY_VOLDWN_MASK        = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
+       TP_ACPI_HKEY_MUTE_MASK          = 1 << TP_ACPI_HOTKEYSCAN_MUTE,
+       TP_ACPI_HKEY_THINKPAD_MASK      = 1 << TP_ACPI_HOTKEYSCAN_THINKPAD,
+};
+
+enum { /* NVRAM to ACPI HKEY group map */
+       TP_NVRAM_HKEY_GROUP_HK2         = TP_ACPI_HKEY_THINKPAD_MASK |
+                                         TP_ACPI_HKEY_ZOOM_MASK |
+                                         TP_ACPI_HKEY_DISPSWTCH_MASK |
+                                         TP_ACPI_HKEY_HIBERNATE_MASK,
+       TP_NVRAM_HKEY_GROUP_BRIGHTNESS  = TP_ACPI_HKEY_BRGHTUP_MASK |
+                                         TP_ACPI_HKEY_BRGHTDWN_MASK,
+       TP_NVRAM_HKEY_GROUP_VOLUME      = TP_ACPI_HKEY_VOLUP_MASK |
+                                         TP_ACPI_HKEY_VOLDWN_MASK |
+                                         TP_ACPI_HKEY_MUTE_MASK,
+};
+
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+struct tp_nvram_state {
+       u16 thinkpad_toggle:1;
+       u16 zoom_toggle:1;
+       u16 display_toggle:1;
+       u16 thinklight_toggle:1;
+       u16 hibernate_toggle:1;
+       u16 displayexp_toggle:1;
+       u16 display_state:1;
+       u16 brightness_toggle:1;
+       u16 volume_toggle:1;
+       u16 mute:1;
+
+       u8 brightness_level;
+       u8 volume_level;
+};
+
+static struct task_struct *tpacpi_hotkey_task;
+static u32 hotkey_source_mask;         /* bit mask 0=ACPI,1=NVRAM */
+static int hotkey_poll_freq = 10;      /* Hz */
+static struct mutex hotkey_thread_mutex;
+static struct mutex hotkey_thread_data_mutex;
+static unsigned int hotkey_config_change;
+
+#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+#define hotkey_source_mask 0U
+
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+static struct mutex hotkey_mutex;
+
+static enum {  /* Reasons for waking up */
+       TP_ACPI_WAKEUP_NONE = 0,        /* None or unknown */
+       TP_ACPI_WAKEUP_BAYEJ,           /* Bay ejection request */
+       TP_ACPI_WAKEUP_UNDOCK,          /* Undock request */
+} hotkey_wakeup_reason;
+
+static int hotkey_autosleep_ack;
+
 static int hotkey_orig_status;
 static u32 hotkey_orig_mask;
 static u32 hotkey_all_mask;
 static u32 hotkey_reserved_mask;
+static u32 hotkey_mask;
+
+static unsigned int hotkey_report_mode;
 
 static u16 *hotkey_keycode_map;
 
 static struct attribute_set *hotkey_dev_attributes;
 
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+#define HOTKEY_CONFIG_CRITICAL_START \
+       do { \
+               mutex_lock(&hotkey_thread_data_mutex); \
+               hotkey_config_change++; \
+       } while (0);
+#define HOTKEY_CONFIG_CRITICAL_END \
+       mutex_unlock(&hotkey_thread_data_mutex);
+#else
+#define HOTKEY_CONFIG_CRITICAL_START
+#define HOTKEY_CONFIG_CRITICAL_END
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
 static int hotkey_get_wlsw(int *status)
 {
        if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@@ -789,15 +1060,400 @@ static int hotkey_get_wlsw(int *status)
        return 0;
 }
 
-/* sysfs hotkey enable ------------------------------------------------- */
-static ssize_t hotkey_enable_show(struct device *dev,
-                          struct device_attribute *attr,
-                          char *buf)
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_mask_get(void)
 {
-       int res, status;
+       u32 m = 0;
+
+       if (tp_features.hotkey_mask) {
+               if (!acpi_evalf(hkey_handle, &m, "DHKN", "d"))
+                       return -EIO;
+       }
+       hotkey_mask = m | (hotkey_source_mask & hotkey_mask);
+
+       return 0;
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_mask_set(u32 mask)
+{
+       int i;
+       int rc = 0;
+
+       if (tp_features.hotkey_mask) {
+               HOTKEY_CONFIG_CRITICAL_START
+               for (i = 0; i < 32; i++) {
+                       u32 m = 1 << i;
+                       /* enable in firmware mask only keys not in NVRAM
+                        * mode, but enable the key in the cached hotkey_mask
+                        * regardless of mode, or the key will end up
+                        * disabled by hotkey_mask_get() */
+                       if (!acpi_evalf(hkey_handle,
+                                       NULL, "MHKM", "vdd", i + 1,
+                                       !!((mask & ~hotkey_source_mask) & m))) {
+                               rc = -EIO;
+                               break;
+                       } else {
+                               hotkey_mask = (hotkey_mask & ~m) | (mask & m);
+                       }
+               }
+               HOTKEY_CONFIG_CRITICAL_END
+
+               /* hotkey_mask_get must be called unconditionally below */
+               if (!hotkey_mask_get() && !rc &&
+                   (hotkey_mask & ~hotkey_source_mask) !=
+                    (mask & ~hotkey_source_mask)) {
+                       printk(TPACPI_NOTICE
+                              "requested hot key mask 0x%08x, but "
+                              "firmware forced it to 0x%08x\n",
+                              mask, hotkey_mask);
+               }
+       } else {
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+               HOTKEY_CONFIG_CRITICAL_START
+               hotkey_mask = mask & hotkey_source_mask;
+               HOTKEY_CONFIG_CRITICAL_END
+               hotkey_mask_get();
+               if (hotkey_mask != mask) {
+                       printk(TPACPI_NOTICE
+                              "requested hot key mask 0x%08x, "
+                              "forced to 0x%08x (NVRAM poll mask is "
+                              "0x%08x): no firmware mask support\n",
+                              mask, hotkey_mask, hotkey_source_mask);
+               }
+#else
+               hotkey_mask_get();
+               rc = -ENXIO;
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+       }
+
+       return rc;
+}
+
+static int hotkey_status_get(int *status)
+{
+       if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
+               return -EIO;
+
+       return 0;
+}
+
+static int hotkey_status_set(int status)
+{
+       if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
+               return -EIO;
+
+       return 0;
+}
+
+static void tpacpi_input_send_radiosw(void)
+{
+       int wlsw;
+
+       mutex_lock(&tpacpi_inputdev_send_mutex);
+
+       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
+               input_report_switch(tpacpi_inputdev,
+                                   SW_RADIO, !!wlsw);
+               input_sync(tpacpi_inputdev);
+       }
+
+       mutex_unlock(&tpacpi_inputdev_send_mutex);
+}
+
+static void tpacpi_input_send_key(unsigned int scancode)
+{
+       unsigned int keycode;
+
+       keycode = hotkey_keycode_map[scancode];
+
+       if (keycode != KEY_RESERVED) {
+               mutex_lock(&tpacpi_inputdev_send_mutex);
+
+               input_report_key(tpacpi_inputdev, keycode, 1);
+               if (keycode == KEY_UNKNOWN)
+                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+                                   scancode);
+               input_sync(tpacpi_inputdev);
+
+               input_report_key(tpacpi_inputdev, keycode, 0);
+               if (keycode == KEY_UNKNOWN)
+                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+                                   scancode);
+               input_sync(tpacpi_inputdev);
+
+               mutex_unlock(&tpacpi_inputdev_send_mutex);
+       }
+}
+
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+static struct tp_acpi_drv_struct ibm_hotkey_acpidriver;
+
+static void tpacpi_hotkey_send_key(unsigned int scancode)
+{
+       tpacpi_input_send_key(scancode);
+       if (hotkey_report_mode < 2) {
+               acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device,
+                                               0x80, 0x1001 + scancode);
+       }
+}
+
+static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m)
+{
+       u8 d;
+
+       if (m & TP_NVRAM_HKEY_GROUP_HK2) {
+               d = nvram_read_byte(TP_NVRAM_ADDR_HK2);
+               n->thinkpad_toggle = !!(d & TP_NVRAM_MASK_HKT_THINKPAD);
+               n->zoom_toggle = !!(d & TP_NVRAM_MASK_HKT_ZOOM);
+               n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY);
+               n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE);
+       }
+       if (m & TP_ACPI_HKEY_THNKLGHT_MASK) {
+               d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT);
+               n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT);
+       }
+       if (m & TP_ACPI_HKEY_DISPXPAND_MASK) {
+               d = nvram_read_byte(TP_NVRAM_ADDR_VIDEO);
+               n->displayexp_toggle =
+                               !!(d & TP_NVRAM_MASK_HKT_DISPEXPND);
+       }
+       if (m & TP_NVRAM_HKEY_GROUP_BRIGHTNESS) {
+               d = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS);
+               n->brightness_level = (d & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+                               >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+               n->brightness_toggle =
+                               !!(d & TP_NVRAM_MASK_HKT_BRIGHTNESS);
+       }
+       if (m & TP_NVRAM_HKEY_GROUP_VOLUME) {
+               d = nvram_read_byte(TP_NVRAM_ADDR_MIXER);
+               n->volume_level = (d & TP_NVRAM_MASK_LEVEL_VOLUME)
+                               >> TP_NVRAM_POS_LEVEL_VOLUME;
+               n->mute = !!(d & TP_NVRAM_MASK_MUTE);
+               n->volume_toggle = !!(d & TP_NVRAM_MASK_HKT_VOLUME);
+       }
+}
+
+#define TPACPI_COMPARE_KEY(__scancode, __member) \
+       do { \
+               if ((mask & (1 << __scancode)) && \
+                   oldn->__member != newn->__member) \
+               tpacpi_hotkey_send_key(__scancode); \
+       } while (0)
+
+#define TPACPI_MAY_SEND_KEY(__scancode) \
+       do { if (mask & (1 << __scancode)) \
+               tpacpi_hotkey_send_key(__scancode); } while (0)
+
+static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
+                                          struct tp_nvram_state *newn,
+                                          u32 mask)
+{
+       TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle);
+       TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle);
+       TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle);
+       TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF12, hibernate_toggle);
+
+       TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNPAGEUP, thinklight_toggle);
+
+       TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle);
+
+       /* handle volume */
+       if (oldn->volume_toggle != newn->volume_toggle) {
+               if (oldn->mute != newn->mute) {
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
+               }
+               if (oldn->volume_level > newn->volume_level) {
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
+               } else if (oldn->volume_level < newn->volume_level) {
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
+               } else if (oldn->mute == newn->mute) {
+                       /* repeated key presses that didn't change state */
+                       if (newn->mute) {
+                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
+                       } else if (newn->volume_level != 0) {
+                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
+                       } else {
+                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
+                       }
+               }
+       }
+
+       /* handle brightness */
+       if (oldn->brightness_toggle != newn->brightness_toggle) {
+               if (oldn->brightness_level < newn->brightness_level) {
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
+               } else if (oldn->brightness_level > newn->brightness_level) {
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
+               } else {
+                       /* repeated key presses that didn't change state */
+                       if (newn->brightness_level != 0) {
+                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
+                       } else {
+                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
+                       }
+               }
+       }
+}
+
+#undef TPACPI_COMPARE_KEY
+#undef TPACPI_MAY_SEND_KEY
+
+static int hotkey_kthread(void *data)
+{
+       struct tp_nvram_state s[2];
        u32 mask;
+       unsigned int si, so;
+       unsigned long t;
+       unsigned int change_detector, must_reset;
+
+       mutex_lock(&hotkey_thread_mutex);
+
+       if (tpacpi_lifecycle == TPACPI_LIFE_EXITING)
+               goto exit;
+
+       set_freezable();
+
+       so = 0;
+       si = 1;
+       t = 0;
+
+       /* Initial state for compares */
+       mutex_lock(&hotkey_thread_data_mutex);
+       change_detector = hotkey_config_change;
+       mask = hotkey_source_mask & hotkey_mask;
+       mutex_unlock(&hotkey_thread_data_mutex);
+       hotkey_read_nvram(&s[so], mask);
+
+       while (!kthread_should_stop() && hotkey_poll_freq) {
+               if (t == 0)
+                       t = 1000/hotkey_poll_freq;
+               t = msleep_interruptible(t);
+               if (unlikely(kthread_should_stop()))
+                       break;
+               must_reset = try_to_freeze();
+               if (t > 0 && !must_reset)
+                       continue;
+
+               mutex_lock(&hotkey_thread_data_mutex);
+               if (must_reset || hotkey_config_change != change_detector) {
+                       /* forget old state on thaw or config change */
+                       si = so;
+                       t = 0;
+                       change_detector = hotkey_config_change;
+               }
+               mask = hotkey_source_mask & hotkey_mask;
+               mutex_unlock(&hotkey_thread_data_mutex);
+
+               if (likely(mask)) {
+                       hotkey_read_nvram(&s[si], mask);
+                       if (likely(si != so)) {
+                               hotkey_compare_and_issue_event(&s[so], &s[si],
+                                                               mask);
+                       }
+               }
+
+               so = si;
+               si ^= 1;
+       }
+
+exit:
+       mutex_unlock(&hotkey_thread_mutex);
+       return 0;
+}
+
+static void hotkey_poll_stop_sync(void)
+{
+       if (tpacpi_hotkey_task) {
+               if (frozen(tpacpi_hotkey_task) ||
+                   freezing(tpacpi_hotkey_task))
+                       thaw_process(tpacpi_hotkey_task);
+
+               kthread_stop(tpacpi_hotkey_task);
+               tpacpi_hotkey_task = NULL;
+               mutex_lock(&hotkey_thread_mutex);
+               /* at this point, the thread did exit */
+               mutex_unlock(&hotkey_thread_mutex);
+       }
+}
+
+/* call with hotkey_mutex held */
+static void hotkey_poll_setup(int may_warn)
+{
+       if ((hotkey_source_mask & hotkey_mask) != 0 &&
+           hotkey_poll_freq > 0 &&
+           (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
+               if (!tpacpi_hotkey_task) {
+                       tpacpi_hotkey_task = kthread_run(hotkey_kthread,
+                                                        NULL,
+                                                        TPACPI_FILE "d");
+                       if (IS_ERR(tpacpi_hotkey_task)) {
+                               tpacpi_hotkey_task = NULL;
+                               printk(TPACPI_ERR
+                                      "could not create kernel thread "
+                                      "for hotkey polling\n");
+                       }
+               }
+       } else {
+               hotkey_poll_stop_sync();
+               if (may_warn &&
+                   hotkey_source_mask != 0 && hotkey_poll_freq == 0) {
+                       printk(TPACPI_NOTICE
+                               "hot keys 0x%08x require polling, "
+                               "which is currently disabled\n",
+                               hotkey_source_mask);
+               }
+       }
+}
+
+static void hotkey_poll_setup_safe(int may_warn)
+{
+       mutex_lock(&hotkey_mutex);
+       hotkey_poll_setup(may_warn);
+       mutex_unlock(&hotkey_mutex);
+}
+
+static int hotkey_inputdev_open(struct input_dev *dev)
+{
+       switch (tpacpi_lifecycle) {
+       case TPACPI_LIFE_INIT:
+               /*
+                * hotkey_init will call hotkey_poll_setup_safe
+                * at the appropriate moment
+                */
+               return 0;
+       case TPACPI_LIFE_EXITING:
+               return -EBUSY;
+       case TPACPI_LIFE_RUNNING:
+               hotkey_poll_setup_safe(0);
+               return 0;
+       }
+
+       /* Should only happen if tpacpi_lifecycle is corrupt */
+       BUG();
+       return -EBUSY;
+}
+
+static void hotkey_inputdev_close(struct input_dev *dev)
+{
+       /* disable hotkey polling when possible */
+       if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
+               hotkey_poll_setup_safe(0);
+}
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+/* sysfs hotkey enable ------------------------------------------------- */
+static ssize_t hotkey_enable_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int res, status;
 
-       res = hotkey_get(&status, &mask);
+       res = hotkey_status_get(&status);
        if (res)
                return res;
 
@@ -809,15 +1465,12 @@ static ssize_t hotkey_enable_store(struct device *dev,
                            const char *buf, size_t count)
 {
        unsigned long t;
-       int res, status;
-       u32 mask;
+       int res;
 
        if (parse_strtoul(buf, 1, &t))
                return -EINVAL;
 
-       res = hotkey_get(&status, &mask);
-       if (!res)
-               res = hotkey_set(t, mask);
+       res = hotkey_status_set(t);
 
        return (res) ? res : count;
 }
@@ -831,14 +1484,15 @@ static ssize_t hotkey_mask_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       int res, status;
-       u32 mask;
+       int res;
 
-       res = hotkey_get(&status, &mask);
-       if (res)
-               return res;
+       if (mutex_lock_interruptible(&hotkey_mutex))
+               return -ERESTARTSYS;
+       res = hotkey_mask_get();
+       mutex_unlock(&hotkey_mutex);
 
-       return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
+       return (res)?
+               res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask);
 }
 
 static ssize_t hotkey_mask_store(struct device *dev,
@@ -846,15 +1500,21 @@ static ssize_t hotkey_mask_store(struct device *dev,
                            const char *buf, size_t count)
 {
        unsigned long t;
-       int res, status;
-       u32 mask;
+       int res;
 
        if (parse_strtoul(buf, 0xffffffffUL, &t))
                return -EINVAL;
 
-       res = hotkey_get(&status, &mask);
-       if (!res)
-               hotkey_set(status, t);
+       if (mutex_lock_interruptible(&hotkey_mutex))
+               return -ERESTARTSYS;
+
+       res = hotkey_mask_set(t);
+
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+       hotkey_poll_setup(1);
+#endif
+
+       mutex_unlock(&hotkey_mutex);
 
        return (res) ? res : count;
 }
@@ -890,7 +1550,8 @@ static ssize_t hotkey_all_mask_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
+       return snprintf(buf, PAGE_SIZE, "0x%08x\n",
+                               hotkey_all_mask | hotkey_source_mask);
 }
 
 static struct device_attribute dev_attr_hotkey_all_mask =
@@ -902,14 +1563,87 @@ static ssize_t hotkey_recommended_mask_show(struct device *dev,
                                            char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "0x%08x\n",
-                       hotkey_all_mask & ~hotkey_reserved_mask);
+                       (hotkey_all_mask | hotkey_source_mask)
+                       & ~hotkey_reserved_mask);
 }
 
 static struct device_attribute dev_attr_hotkey_recommended_mask =
        __ATTR(hotkey_recommended_mask, S_IRUGO,
                hotkey_recommended_mask_show, NULL);
 
-/* sysfs hotkey radio_sw ----------------------------------------------- */
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+
+/* sysfs hotkey hotkey_source_mask ------------------------------------- */
+static ssize_t hotkey_source_mask_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_source_mask);
+}
+
+static ssize_t hotkey_source_mask_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 0xffffffffUL, &t) ||
+               ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0))
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&hotkey_mutex))
+               return -ERESTARTSYS;
+
+       HOTKEY_CONFIG_CRITICAL_START
+       hotkey_source_mask = t;
+       HOTKEY_CONFIG_CRITICAL_END
+
+       hotkey_poll_setup(1);
+
+       mutex_unlock(&hotkey_mutex);
+
+       return count;
+}
+
+static struct device_attribute dev_attr_hotkey_source_mask =
+       __ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO,
+               hotkey_source_mask_show, hotkey_source_mask_store);
+
+/* sysfs hotkey hotkey_poll_freq --------------------------------------- */
+static ssize_t hotkey_poll_freq_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_poll_freq);
+}
+
+static ssize_t hotkey_poll_freq_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 25, &t))
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&hotkey_mutex))
+               return -ERESTARTSYS;
+
+       hotkey_poll_freq = t;
+
+       hotkey_poll_setup(1);
+       mutex_unlock(&hotkey_mutex);
+
+       return count;
+}
+
+static struct device_attribute dev_attr_hotkey_poll_freq =
+       __ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO,
+               hotkey_poll_freq_show, hotkey_poll_freq_store);
+
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+/* sysfs hotkey radio_sw (pollable) ------------------------------------ */
 static ssize_t hotkey_radio_sw_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
@@ -925,6 +1659,13 @@ static ssize_t hotkey_radio_sw_show(struct device *dev,
 static struct device_attribute dev_attr_hotkey_radio_sw =
        __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
 
+static void hotkey_radio_sw_notify_change(void)
+{
+       if (tp_features.hotkey_wlsw)
+               sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
+                            "hotkey_radio_sw");
+}
+
 /* sysfs hotkey report_mode -------------------------------------------- */
 static ssize_t hotkey_report_mode_show(struct device *dev,
                           struct device_attribute *attr,
@@ -937,43 +1678,132 @@ static ssize_t hotkey_report_mode_show(struct device *dev,
 static struct device_attribute dev_attr_hotkey_report_mode =
        __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
 
-/* --------------------------------------------------------------------- */
+/* sysfs wakeup reason (pollable) -------------------------------------- */
+static ssize_t hotkey_wakeup_reason_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason);
+}
 
-static struct attribute *hotkey_attributes[] __initdata = {
-       &dev_attr_hotkey_enable.attr,
-       &dev_attr_hotkey_report_mode.attr,
-};
+static struct device_attribute dev_attr_hotkey_wakeup_reason =
+       __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL);
 
-static struct attribute *hotkey_mask_attributes[] __initdata = {
-       &dev_attr_hotkey_mask.attr,
+void hotkey_wakeup_reason_notify_change(void)
+{
+       if (tp_features.hotkey_mask)
+               sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
+                            "wakeup_reason");
+}
+
+/* sysfs wakeup hotunplug_complete (pollable) -------------------------- */
+static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack);
+}
+
+static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete =
+       __ATTR(wakeup_hotunplug_complete, S_IRUGO,
+              hotkey_wakeup_hotunplug_complete_show, NULL);
+
+void hotkey_wakeup_hotunplug_complete_notify_change(void)
+{
+       if (tp_features.hotkey_mask)
+               sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
+                            "wakeup_hotunplug_complete");
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *hotkey_attributes[] __initdata = {
+       &dev_attr_hotkey_enable.attr,
        &dev_attr_hotkey_bios_enabled.attr,
+       &dev_attr_hotkey_report_mode.attr,
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+       &dev_attr_hotkey_mask.attr,
+       &dev_attr_hotkey_all_mask.attr,
+       &dev_attr_hotkey_recommended_mask.attr,
+       &dev_attr_hotkey_source_mask.attr,
+       &dev_attr_hotkey_poll_freq.attr,
+#endif
+};
+
+static struct attribute *hotkey_mask_attributes[] __initdata = {
        &dev_attr_hotkey_bios_mask.attr,
+#ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+       &dev_attr_hotkey_mask.attr,
        &dev_attr_hotkey_all_mask.attr,
        &dev_attr_hotkey_recommended_mask.attr,
+#endif
+       &dev_attr_hotkey_wakeup_reason.attr,
+       &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
 };
 
 static int __init hotkey_init(struct ibm_init_struct *iibm)
 {
-
+       /* Requirements for changing the default keymaps:
+        *
+        * 1. Many of the keys are mapped to KEY_RESERVED for very
+        *    good reasons.  Do not change them unless you have deep
+        *    knowledge on the IBM and Lenovo ThinkPad firmware for
+        *    the various ThinkPad models.  The driver behaves
+        *    differently for KEY_RESERVED: such keys have their
+        *    hot key mask *unset* in mask_recommended, and also
+        *    in the initial hot key mask programmed into the
+        *    firmware at driver load time, which means the firm-
+        *    ware may react very differently if you change them to
+        *    something else;
+        *
+        * 2. You must be subscribed to the linux-thinkpad and
+        *    ibm-acpi-devel mailing lists, and you should read the
+        *    list archives since 2007 if you want to change the
+        *    keymaps.  This requirement exists so that you will
+        *    know the past history of problems with the thinkpad-
+        *    acpi driver keymaps, and also that you will be
+        *    listening to any bug reports;
+        *
+        * 3. Do not send thinkpad-acpi specific patches directly to
+        *    for merging, *ever*.  Send them to the linux-acpi
+        *    mailinglist for comments.  Merging is to be done only
+        *    through acpi-test and the ACPI maintainer.
+        *
+        * If the above is too much to ask, don't change the keymap.
+        * Ask the thinkpad-acpi maintainer to do it, instead.
+        */
        static u16 ibm_keycode_map[] __initdata = {
                /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
                KEY_FN_F1,      KEY_FN_F2,      KEY_COFFEE,     KEY_SLEEP,
                KEY_WLAN,       KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
                KEY_FN_F9,      KEY_FN_F10,     KEY_FN_F11,     KEY_SUSPEND,
-               /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+
+               /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */
                KEY_UNKNOWN,    /* 0x0C: FN+BACKSPACE */
                KEY_UNKNOWN,    /* 0x0D: FN+INSERT */
                KEY_UNKNOWN,    /* 0x0E: FN+DELETE */
+
+               /* brightness: firmware always reacts to them, unless
+                * X.org did some tricks in the radeon BIOS scratch
+                * registers of *some* models */
                KEY_RESERVED,   /* 0x0F: FN+HOME (brightness up) */
-               /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
                KEY_RESERVED,   /* 0x10: FN+END (brightness down) */
+
+               /* Thinklight: firmware always react to it */
                KEY_RESERVED,   /* 0x11: FN+PGUP (thinklight toggle) */
+
                KEY_UNKNOWN,    /* 0x12: FN+PGDOWN */
                KEY_ZOOM,       /* 0x13: FN+SPACE (zoom) */
+
+               /* Volume: firmware always react to it and reprograms
+                * the built-in *extra* mixer.  Never map it to control
+                * another mixer by default. */
                KEY_RESERVED,   /* 0x14: VOLUME UP */
                KEY_RESERVED,   /* 0x15: VOLUME DOWN */
                KEY_RESERVED,   /* 0x16: MUTE */
+
                KEY_VENDOR,     /* 0x17: Thinkpad/AccessIBM/Lenovo */
+
                /* (assignments unknown, please report if found) */
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -983,20 +1813,37 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                KEY_FN_F1,      KEY_COFFEE,     KEY_BATTERY,    KEY_SLEEP,
                KEY_WLAN,       KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
                KEY_FN_F9,      KEY_FN_F10,     KEY_FN_F11,     KEY_SUSPEND,
-               /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+
+               /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */
                KEY_UNKNOWN,    /* 0x0C: FN+BACKSPACE */
                KEY_UNKNOWN,    /* 0x0D: FN+INSERT */
                KEY_UNKNOWN,    /* 0x0E: FN+DELETE */
+
                KEY_RESERVED,   /* 0x0F: FN+HOME (brightness up) */
-               /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
                KEY_RESERVED,   /* 0x10: FN+END (brightness down) */
+
                KEY_RESERVED,   /* 0x11: FN+PGUP (thinklight toggle) */
+
                KEY_UNKNOWN,    /* 0x12: FN+PGDOWN */
                KEY_ZOOM,       /* 0x13: FN+SPACE (zoom) */
+
+               /* Volume: z60/z61, T60 (BIOS version?): firmware always
+                * react to it and reprograms the built-in *extra* mixer.
+                * Never map it to control another mixer by default.
+                *
+                * T60?, T61, R60?, R61: firmware and EC tries to send
+                * these over the regular keyboard, so these are no-ops,
+                * but there are still weird bugs re. MUTE, so do not
+                * change unless you get test reports from all Lenovo
+                * models.  May cause the BIOS to interfere with the
+                * HDA mixer.
+                */
                KEY_RESERVED,   /* 0x14: VOLUME UP */
                KEY_RESERVED,   /* 0x15: VOLUME DOWN */
                KEY_RESERVED,   /* 0x16: MUTE */
+
                KEY_VENDOR,     /* 0x17: Thinkpad/AccessIBM/Lenovo */
+
                /* (assignments unknown, please report if found) */
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -1013,10 +1860,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
        vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
 
        BUG_ON(!tpacpi_inputdev);
+       BUG_ON(tpacpi_inputdev->open != NULL ||
+              tpacpi_inputdev->close != NULL);
 
-       IBM_ACPIHANDLE_INIT(hkey);
+       TPACPI_ACPIHANDLE_INIT(hkey);
        mutex_init(&hotkey_mutex);
 
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+       mutex_init(&hotkey_thread_mutex);
+       mutex_init(&hotkey_thread_data_mutex);
+#endif
+
        /* hotkey not supported on 570 */
        tp_features.hotkey = hkey_handle != NULL;
 
@@ -1024,7 +1878,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                str_supported(tp_features.hotkey));
 
        if (tp_features.hotkey) {
-               hotkey_dev_attributes = create_attr_set(8, NULL);
+               hotkey_dev_attributes = create_attr_set(12, NULL);
                if (!hotkey_dev_attributes)
                        return -ENOMEM;
                res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1038,15 +1892,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                   for HKEY interface version 0x100 */
                if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
                        if ((hkeyv >> 8) != 1) {
-                               printk(IBM_ERR "unknown version of the "
+                               printk(TPACPI_ERR "unknown version of the "
                                       "HKEY interface: 0x%x\n", hkeyv);
-                               printk(IBM_ERR "please report this to %s\n",
-                                      IBM_MAIL);
+                               printk(TPACPI_ERR "please report this to %s\n",
+                                      TPACPI_MAIL);
                        } else {
                                /*
                                 * MHKV 0x100 in A31, R40, R40e,
                                 * T4x, X31, and later
-                                * */
+                                */
                                tp_features.hotkey_mask = 1;
                        }
                }
@@ -1057,25 +1911,46 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                if (tp_features.hotkey_mask) {
                        if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
                                        "MHKA", "qd")) {
-                               printk(IBM_ERR
+                               printk(TPACPI_ERR
                                       "missing MHKA handler, "
                                       "please report this to %s\n",
-                                      IBM_MAIL);
-                               hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+                                      TPACPI_MAIL);
+                               /* FN+F12, FN+F4, FN+F3 */
+                               hotkey_all_mask = 0x080cU;
                        }
                }
 
-               res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
+               /* hotkey_source_mask *must* be zero for
+                * the first hotkey_mask_get */
+               res = hotkey_status_get(&hotkey_orig_status);
                if (!res && tp_features.hotkey_mask) {
-                       res = add_many_to_attr_set(hotkey_dev_attributes,
-                               hotkey_mask_attributes,
-                               ARRAY_SIZE(hotkey_mask_attributes));
+                       res = hotkey_mask_get();
+                       hotkey_orig_mask = hotkey_mask;
+                       if (!res) {
+                               res = add_many_to_attr_set(
+                                       hotkey_dev_attributes,
+                                       hotkey_mask_attributes,
+                                       ARRAY_SIZE(hotkey_mask_attributes));
+                       }
+               }
+
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+               if (tp_features.hotkey_mask) {
+                       hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
+                                               & ~hotkey_all_mask;
+               } else {
+                       hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
                }
 
+               vdbg_printk(TPACPI_DBG_INIT,
+                           "hotkey source mask 0x%08x, polling freq %d\n",
+                           hotkey_source_mask, hotkey_poll_freq);
+#endif
+
                /* Not all thinkpads have a hardware radio switch */
                if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
                        tp_features.hotkey_wlsw = 1;
-                       printk(IBM_INFO
+                       printk(TPACPI_INFO
                                "radio switch found; radios are %s\n",
                                enabled(status, 0));
                        res = add_to_attr_set(hotkey_dev_attributes,
@@ -1094,7 +1969,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
                                                GFP_KERNEL);
                if (!hotkey_keycode_map) {
-                       printk(IBM_ERR "failed to allocate memory for key map\n");
+                       printk(TPACPI_ERR
+                               "failed to allocate memory for key map\n");
                        return -ENOMEM;
                }
 
@@ -1133,15 +2009,26 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 
                dbg_printk(TPACPI_DBG_INIT,
                                "enabling hot key handling\n");
-               res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
-                                       | hotkey_orig_mask);
+               res = hotkey_status_set(1);
                if (res)
                        return res;
+               res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
+                                       & ~hotkey_reserved_mask)
+                                       | hotkey_orig_mask);
+               if (res < 0 && res != -ENXIO)
+                       return res;
 
                dbg_printk(TPACPI_DBG_INIT,
                                "legacy hot key reporting over procfs %s\n",
                                (hotkey_report_mode < 2) ?
                                        "enabled" : "disabled");
+
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+               tpacpi_inputdev->open = &hotkey_inputdev_open;
+               tpacpi_inputdev->close = &hotkey_inputdev_close;
+
+               hotkey_poll_setup_safe(1);
+#endif
        }
 
        return (tp_features.hotkey)? 0 : 1;
@@ -1149,13 +2036,19 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 
 static void hotkey_exit(void)
 {
-       int res;
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+       hotkey_poll_stop_sync();
+#endif
 
        if (tp_features.hotkey) {
-               dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n");
-               res = hotkey_set(hotkey_orig_status, hotkey_orig_mask);
-               if (res)
-                       printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n");
+               dbg_printk(TPACPI_DBG_EXIT,
+                          "restoring original hot key mask\n");
+               /* no short-circuit boolean operator below! */
+               if ((hotkey_mask_set(hotkey_orig_mask) |
+                    hotkey_status_set(hotkey_orig_status)) != 0)
+                       printk(TPACPI_ERR
+                              "failed to restore hot key mask "
+                              "to BIOS defaults\n");
        }
 
        if (hotkey_dev_attributes) {
@@ -1164,62 +2057,28 @@ static void hotkey_exit(void)
        }
 }
 
-static void tpacpi_input_send_key(unsigned int scancode,
-                                 unsigned int keycode)
-{
-       if (keycode != KEY_RESERVED) {
-               mutex_lock(&tpacpi_inputdev_send_mutex);
-
-               input_report_key(tpacpi_inputdev, keycode, 1);
-               if (keycode == KEY_UNKNOWN)
-                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
-                                   scancode);
-               input_sync(tpacpi_inputdev);
-
-               input_report_key(tpacpi_inputdev, keycode, 0);
-               if (keycode == KEY_UNKNOWN)
-                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
-                                   scancode);
-               input_sync(tpacpi_inputdev);
-
-               mutex_unlock(&tpacpi_inputdev_send_mutex);
-       }
-}
-
-static void tpacpi_input_send_radiosw(void)
-{
-       int wlsw;
-
-       mutex_lock(&tpacpi_inputdev_send_mutex);
-
-       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
-               input_report_switch(tpacpi_inputdev,
-                                   SW_RADIO, !!wlsw);
-               input_sync(tpacpi_inputdev);
-       }
-
-       mutex_unlock(&tpacpi_inputdev_send_mutex);
-}
-
 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 {
        u32 hkey;
-       unsigned int keycode, scancode;
+       unsigned int scancode;
        int send_acpi_ev;
        int ignore_acpi_ev;
+       int unk_ev;
 
        if (event != 0x80) {
-               printk(IBM_ERR "unknown HKEY notification event %d\n", event);
+               printk(TPACPI_ERR
+                      "unknown HKEY notification event %d\n", event);
                /* forward it to userspace, maybe it knows how to handle it */
-               acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
-                                               ibm->acpi->device->dev.bus_id,
-                                               event, 0);
+               acpi_bus_generate_netlink_event(
+                                       ibm->acpi->device->pnp.device_class,
+                                       ibm->acpi->device->dev.bus_id,
+                                       event, 0);
                return;
        }
 
        while (1) {
                if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
-                       printk(IBM_ERR "failed to retrieve HKEY event\n");
+                       printk(TPACPI_ERR "failed to retrieve HKEY event\n");
                        return;
                }
 
@@ -1228,8 +2087,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                        return;
                }
 
-               send_acpi_ev = 0;
+               send_acpi_ev = 1;
                ignore_acpi_ev = 0;
+               unk_ev = 0;
 
                switch (hkey >> 12) {
                case 1:
@@ -1237,104 +2097,139 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                        scancode = hkey & 0xfff;
                        if (scancode > 0 && scancode < 0x21) {
                                scancode--;
-                               keycode = hotkey_keycode_map[scancode];
-                               tpacpi_input_send_key(scancode, keycode);
+                               if (!(hotkey_source_mask & (1 << scancode))) {
+                                       tpacpi_input_send_key(scancode);
+                                       send_acpi_ev = 0;
+                               } else {
+                                       ignore_acpi_ev = 1;
+                               }
                        } else {
-                               printk(IBM_ERR
-                                      "hotkey 0x%04x out of range for keyboard map\n",
-                                      hkey);
-                               send_acpi_ev = 1;
+                               unk_ev = 1;
                        }
                        break;
-               case 5:
-                       /* 0x5000-0x5FFF: LID */
-                       /* we don't handle it through this path, just
-                        * eat up known LID events */
-                       if (hkey != 0x5001 && hkey != 0x5002) {
-                               printk(IBM_ERR
-                                      "unknown LID-related HKEY event: 0x%04x\n",
-                                      hkey);
-                               send_acpi_ev = 1;
+               case 2:
+                       /* Wakeup reason */
+                       switch (hkey) {
+                       case 0x2304: /* suspend, undock */
+                       case 0x2404: /* hibernation, undock */
+                               hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
+                               ignore_acpi_ev = 1;
+                               break;
+                       case 0x2305: /* suspend, bay eject */
+                       case 0x2405: /* hibernation, bay eject */
+                               hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
+                               ignore_acpi_ev = 1;
+                               break;
+                       default:
+                               unk_ev = 1;
+                       }
+                       if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
+                               printk(TPACPI_INFO
+                                      "woke up due to a hot-unplug "
+                                      "request...\n");
+                               hotkey_wakeup_reason_notify_change();
+                       }
+                       break;
+               case 3:
+                       /* bay-related wakeups */
+                       if (hkey == 0x3003) {
+                               hotkey_autosleep_ack = 1;
+                               printk(TPACPI_INFO
+                                      "bay ejected\n");
+                               hotkey_wakeup_hotunplug_complete_notify_change();
+                       } else {
+                               unk_ev = 1;
+                       }
+                       break;
+               case 4:
+                       /* dock-related wakeups */
+                       if (hkey == 0x4003) {
+                               hotkey_autosleep_ack = 1;
+                               printk(TPACPI_INFO
+                                      "undocked\n");
+                               hotkey_wakeup_hotunplug_complete_notify_change();
                        } else {
+                               unk_ev = 1;
+                       }
+                       break;
+               case 5:
+                       /* 0x5000-0x5FFF: human interface helpers */
+                       switch (hkey) {
+                       case 0x5010: /* Lenovo new BIOS: brightness changed */
+                       case 0x5009: /* X61t: swivel up (tablet mode) */
+                       case 0x500a: /* X61t: swivel down (normal mode) */
+                       case 0x500b: /* X61t: tablet pen inserted into bay */
+                       case 0x500c: /* X61t: tablet pen removed from bay */
+                               break;
+                       case 0x5001:
+                       case 0x5002:
+                               /* LID switch events.  Do not propagate */
                                ignore_acpi_ev = 1;
+                               break;
+                       default:
+                               unk_ev = 1;
                        }
                        break;
                case 7:
                        /* 0x7000-0x7FFF: misc */
                        if (tp_features.hotkey_wlsw && hkey == 0x7000) {
                                tpacpi_input_send_radiosw();
+                               hotkey_radio_sw_notify_change();
+                               send_acpi_ev = 0;
                                break;
                        }
                        /* fallthrough to default */
                default:
-                       /* case 2: dock-related */
-                       /*      0x2305 - T43 waking up due to bay lever eject while aslept */
-                       /* case 3: ultra-bay related. maybe bay in dock? */
-                       /*      0x3003 - T43 after wake up by bay lever eject (0x2305) */
-                       printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
-                       send_acpi_ev = 1;
+                       unk_ev = 1;
+               }
+               if (unk_ev) {
+                       printk(TPACPI_NOTICE
+                              "unhandled HKEY event 0x%04x\n", hkey);
                }
 
                /* Legacy events */
-               if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) {
-                       acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+               if (!ignore_acpi_ev &&
+                   (send_acpi_ev || hotkey_report_mode < 2)) {
+                       acpi_bus_generate_proc_event(ibm->acpi->device,
+                                                    event, hkey);
                }
 
                /* netlink events */
                if (!ignore_acpi_ev && send_acpi_ev) {
-                       acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
-                                                       ibm->acpi->device->dev.bus_id,
-                                                       event, hkey);
+                       acpi_bus_generate_netlink_event(
+                                       ibm->acpi->device->pnp.device_class,
+                                       ibm->acpi->device->dev.bus_id,
+                                       event, hkey);
                }
        }
 }
 
-static void hotkey_resume(void)
-{
-       tpacpi_input_send_radiosw();
-}
-
-/*
- * Call with hotkey_mutex held
- */
-static int hotkey_get(int *status, u32 *mask)
+static void hotkey_suspend(pm_message_t state)
 {
-       if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
-               return -EIO;
-
-       if (tp_features.hotkey_mask)
-               if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
-                       return -EIO;
-
-       return 0;
+       /* Do these on suspend, we get the events on early resume! */
+       hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
+       hotkey_autosleep_ack = 0;
 }
 
-/*
- * Call with hotkey_mutex held
- */
-static int hotkey_set(int status, u32 mask)
+static void hotkey_resume(void)
 {
-       int i;
-
-       if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
-               return -EIO;
-
-       if (tp_features.hotkey_mask)
-               for (i = 0; i < 32; i++) {
-                       int bit = ((1 << i) & mask) != 0;
-                       if (!acpi_evalf(hkey_handle,
-                                       NULL, "MHKM", "vdd", i + 1, bit))
-                               return -EIO;
-               }
-
-       return 0;
+       if (hotkey_mask_get())
+               printk(TPACPI_ERR
+                      "error while trying to read hot key mask "
+                      "from firmware\n");
+       tpacpi_input_send_radiosw();
+       hotkey_radio_sw_notify_change();
+       hotkey_wakeup_reason_notify_change();
+       hotkey_wakeup_hotunplug_complete_notify_change();
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+       hotkey_poll_setup_safe(0);
+#endif
 }
 
 /* procfs -------------------------------------------------------------- */
 static int hotkey_read(char *p)
 {
        int res, status;
-       u32 mask;
        int len = 0;
 
        if (!tp_features.hotkey) {
@@ -1344,14 +2239,16 @@ static int hotkey_read(char *p)
 
        if (mutex_lock_interruptible(&hotkey_mutex))
                return -ERESTARTSYS;
-       res = hotkey_get(&status, &mask);
+       res = hotkey_status_get(&status);
+       if (!res)
+               res = hotkey_mask_get();
        mutex_unlock(&hotkey_mutex);
        if (res)
                return res;
 
        len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
        if (tp_features.hotkey_mask) {
-               len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
+               len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask);
                len += sprintf(p + len,
                               "commands:\tenable, disable, reset, <mask>\n");
        } else {
@@ -1367,7 +2264,6 @@ static int hotkey_write(char *buf)
        int res, status;
        u32 mask;
        char *cmd;
-       int do_cmd = 0;
 
        if (!tp_features.hotkey)
                return -ENODEV;
@@ -1375,9 +2271,8 @@ static int hotkey_write(char *buf)
        if (mutex_lock_interruptible(&hotkey_mutex))
                return -ERESTARTSYS;
 
-       res = hotkey_get(&status, &mask);
-       if (res)
-               goto errexit;
+       status = -1;
+       mask = hotkey_mask;
 
        res = 0;
        while ((cmd = next_cmd(&buf))) {
@@ -1396,11 +2291,12 @@ static int hotkey_write(char *buf)
                        res = -EINVAL;
                        goto errexit;
                }
-               do_cmd = 1;
        }
+       if (status != -1)
+               res = hotkey_status_set(status);
 
-       if (do_cmd)
-               res = hotkey_set(status, mask);
+       if (!res && mask != hotkey_mask)
+               res = hotkey_mask_set(mask);
 
 errexit:
        mutex_unlock(&hotkey_mutex);
@@ -1408,7 +2304,7 @@ errexit:
 }
 
 static const struct acpi_device_id ibm_htk_device_ids[] = {
-       {IBM_HKEY_HID, 0},
+       {TPACPI_ACPI_HKEY_HID, 0},
        {"", 0},
 };
 
@@ -1425,6 +2321,7 @@ static struct ibm_struct hotkey_driver_data = {
        .write = hotkey_write,
        .exit = hotkey_exit,
        .resume = hotkey_resume,
+       .suspend = hotkey_suspend,
        .acpi = &ibm_hotkey_acpidriver,
 };
 
@@ -1432,6 +2329,16 @@ static struct ibm_struct hotkey_driver_data = {
  * Bluetooth subdriver
  */
 
+enum {
+       /* ACPI GBDC/SBDC bits */
+       TP_ACPI_BLUETOOTH_HWPRESENT     = 0x01, /* Bluetooth hw available */
+       TP_ACPI_BLUETOOTH_RADIOSSW      = 0x02, /* Bluetooth radio enabled */
+       TP_ACPI_BLUETOOTH_UNK           = 0x04, /* unknown function */
+};
+
+static int bluetooth_get_radiosw(void);
+static int bluetooth_set_radiosw(int radio_on);
+
 /* sysfs bluetooth enable ---------------------------------------------- */
 static ssize_t bluetooth_enable_show(struct device *dev,
                           struct device_attribute *attr,
@@ -1483,7 +2390,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
 
        vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
 
-       IBM_ACPIHANDLE_INIT(hkey);
+       TPACPI_ACPIHANDLE_INIT(hkey);
 
        /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
           G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
@@ -1596,6 +2503,16 @@ static struct ibm_struct bluetooth_driver_data = {
  * Wan subdriver
  */
 
+enum {
+       /* ACPI GWAN/SWAN bits */
+       TP_ACPI_WANCARD_HWPRESENT       = 0x01, /* Wan hw available */
+       TP_ACPI_WANCARD_RADIOSSW        = 0x02, /* Wan radio enabled */
+       TP_ACPI_WANCARD_UNK             = 0x04, /* unknown function */
+};
+
+static int wan_get_radiosw(void);
+static int wan_set_radiosw(int radio_on);
+
 /* sysfs wan enable ---------------------------------------------------- */
 static ssize_t wan_enable_show(struct device *dev,
                           struct device_attribute *attr,
@@ -1647,7 +2564,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
 
        vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
 
-       IBM_ACPIHANDLE_INIT(hkey);
+       TPACPI_ACPIHANDLE_INIT(hkey);
 
        tp_features.wan = hkey_handle &&
            acpi_evalf(hkey_handle, &status, "GWAN", "qd");
@@ -1759,17 +2676,41 @@ static struct ibm_struct wan_driver_data = {
  * Video subdriver
  */
 
+enum video_access_mode {
+       TPACPI_VIDEO_NONE = 0,
+       TPACPI_VIDEO_570,       /* 570 */
+       TPACPI_VIDEO_770,       /* 600e/x, 770e, 770x */
+       TPACPI_VIDEO_NEW,       /* all others */
+};
+
+enum { /* video status flags, based on VIDEO_570 */
+       TP_ACPI_VIDEO_S_LCD = 0x01,     /* LCD output enabled */
+       TP_ACPI_VIDEO_S_CRT = 0x02,     /* CRT output enabled */
+       TP_ACPI_VIDEO_S_DVI = 0x08,     /* DVI output enabled */
+};
+
+enum {  /* TPACPI_VIDEO_570 constants */
+       TP_ACPI_VIDEO_570_PHSCMD = 0x87,        /* unknown magic constant :( */
+       TP_ACPI_VIDEO_570_PHSMASK = 0x03,       /* PHS bits that map to
+                                                * video_status_flags */
+       TP_ACPI_VIDEO_570_PHS2CMD = 0x8b,       /* unknown magic constant :( */
+       TP_ACPI_VIDEO_570_PHS2SET = 0x80,       /* unknown magic constant :( */
+};
+
 static enum video_access_mode video_supported;
 static int video_orig_autosw;
 
-IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",     /* 570 */
+static int video_autosw_get(void);
+static int video_autosw_set(int enable);
+
+TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",  /* 570 */
           "\\_SB.PCI0.AGP0.VID0",      /* 600e/x, 770x */
           "\\_SB.PCI0.VID0",   /* 770e */
           "\\_SB.PCI0.VID",    /* A21e, G4x, R50e, X30, X40 */
           "\\_SB.PCI0.AGP.VID",        /* all others */
           );                           /* R30, R31 */
 
-IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
+TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID");      /* G41 */
 
 static int __init video_init(struct ibm_init_struct *iibm)
 {
@@ -1777,8 +2718,8 @@ static int __init video_init(struct ibm_init_struct *iibm)
 
        vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
 
-       IBM_ACPIHANDLE_INIT(vid);
-       IBM_ACPIHANDLE_INIT(vid2);
+       TPACPI_ACPIHANDLE_INIT(vid);
+       TPACPI_ACPIHANDLE_INIT(vid2);
 
        if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
                /* G41, assume IVGA doesn't change */
@@ -1809,7 +2750,7 @@ static void video_exit(void)
        dbg_printk(TPACPI_DBG_EXIT,
                   "restoring original video autoswitch mode\n");
        if (video_autosw_set(video_orig_autosw))
-               printk(IBM_ERR "error while trying to restore original "
+               printk(TPACPI_ERR "error while trying to restore original "
                        "video autoswitch mode\n");
 }
 
@@ -1882,13 +2823,14 @@ static int video_outputsw_set(int status)
                res = acpi_evalf(vid_handle, NULL,
                                 "ASWT", "vdd", status * 0x100, 0);
                if (!autosw && video_autosw_set(autosw)) {
-                       printk(IBM_ERR "video auto-switch left enabled due to error\n");
+                       printk(TPACPI_ERR
+                              "video auto-switch left enabled due to error\n");
                        return -EIO;
                }
                break;
        case TPACPI_VIDEO_NEW:
                res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
-                       acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
+                     acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
                break;
        default:
                return -ENOSYS;
@@ -1951,7 +2893,8 @@ static int video_outputsw_cycle(void)
                return -ENOSYS;
        }
        if (!autosw && video_autosw_set(autosw)) {
-               printk(IBM_ERR "video auto-switch left enabled due to error\n");
+               printk(TPACPI_ERR
+                      "video auto-switch left enabled due to error\n");
                return -EIO;
        }
 
@@ -2080,16 +3023,16 @@ static struct ibm_struct video_driver_data = {
  * Light (thinklight) subdriver
  */
 
-IBM_HANDLE(lght, root, "\\LGHT");      /* A21e, A2xm/p, T20-22, X20-21 */
-IBM_HANDLE(ledb, ec, "LEDB");          /* G4x */
+TPACPI_HANDLE(lght, root, "\\LGHT");   /* A21e, A2xm/p, T20-22, X20-21 */
+TPACPI_HANDLE(ledb, ec, "LEDB");               /* G4x */
 
 static int __init light_init(struct ibm_init_struct *iibm)
 {
        vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
 
-       IBM_ACPIHANDLE_INIT(ledb);
-       IBM_ACPIHANDLE_INIT(lght);
-       IBM_ACPIHANDLE_INIT(cmos);
+       TPACPI_ACPIHANDLE_INIT(ledb);
+       TPACPI_ACPIHANDLE_INIT(lght);
+       TPACPI_ACPIHANDLE_INIT(cmos);
 
        /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
        tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
@@ -2167,14 +3110,18 @@ static struct ibm_struct light_driver_data = {
 
 #ifdef CONFIG_THINKPAD_ACPI_DOCK
 
-IBM_HANDLE(dock, root, "\\_SB.GDCK",   /* X30, X31, X40 */
+static void dock_notify(struct ibm_struct *ibm, u32 event);
+static int dock_read(char *p);
+static int dock_write(char *buf);
+
+TPACPI_HANDLE(dock, root, "\\_SB.GDCK",        /* X30, X31, X40 */
           "\\_SB.PCI0.DOCK",   /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
           "\\_SB.PCI0.PCI1.DOCK",      /* all others */
           "\\_SB.PCI.ISA.SLCE",        /* 570 */
     );                         /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
 
 /* don't list other alternatives as we install a notify handler on the 570 */
-IBM_HANDLE(pci, root, "\\_SB.PCI");    /* 570 */
+TPACPI_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
 
 static const struct acpi_device_id ibm_pci_device_ids[] = {
        {PCI_ROOT_HID_STRING, 0},
@@ -2217,7 +3164,7 @@ static int __init dock_init(struct ibm_init_struct *iibm)
 {
        vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
 
-       IBM_ACPIHANDLE_INIT(dock);
+       TPACPI_ACPIHANDLE_INIT(dock);
 
        vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
                str_supported(dock_handle != NULL));
@@ -2233,7 +3180,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm)
 
        if (dock_driver_data[0].flags.acpi_driver_registered &&
            dock_driver_data[0].flags.acpi_notify_installed) {
-               IBM_ACPIHANDLE_INIT(pci);
+               TPACPI_ACPIHANDLE_INIT(pci);
                dock2_needed = (pci_handle != NULL);
                vdbg_printk(TPACPI_DBG_INIT,
                            "dock PCI handler for the TP 570 is %s\n",
@@ -2265,7 +3212,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event)
        else if (event == 0 && docked)
                data = 3;       /* dock */
        else {
-               printk(IBM_ERR "unknown dock event %d, status %d\n",
+               printk(TPACPI_ERR "unknown dock event %d, status %d\n",
                       event, _sta(dock_handle));
                data = 0;       /* unknown */
        }
@@ -2321,18 +3268,19 @@ static int dock_write(char *buf)
  */
 
 #ifdef CONFIG_THINKPAD_ACPI_BAY
-IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST",       /* 570 */
+
+TPACPI_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST",    /* 570 */
           "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
           "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
           "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
           );                           /* A21e, R30, R31 */
-IBM_HANDLE(bay_ej, bay, "_EJ3",        /* 600e/x, A2xm/p, A3x */
+TPACPI_HANDLE(bay_ej, bay, "_EJ3",     /* 600e/x, A2xm/p, A3x */
           "_EJ0",              /* all others */
           );                   /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
-IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV",    /* A3x, R32 */
+TPACPI_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
           "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
           );                           /* all others */
-IBM_HANDLE(bay2_ej, bay2, "_EJ3",      /* 600e/x, 770e, A3x */
+TPACPI_HANDLE(bay2_ej, bay2, "_EJ3",   /* 600e/x, 770e, A3x */
           "_EJ0",                      /* 770x */
           );                           /* all others */
 
@@ -2340,12 +3288,12 @@ static int __init bay_init(struct ibm_init_struct *iibm)
 {
        vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
 
-       IBM_ACPIHANDLE_INIT(bay);
+       TPACPI_ACPIHANDLE_INIT(bay);
        if (bay_handle)
-               IBM_ACPIHANDLE_INIT(bay_ej);
-       IBM_ACPIHANDLE_INIT(bay2);
+               TPACPI_ACPIHANDLE_INIT(bay_ej);
+       TPACPI_ACPIHANDLE_INIT(bay2);
        if (bay2_handle)
-               IBM_ACPIHANDLE_INIT(bay2_ej);
+               TPACPI_ACPIHANDLE_INIT(bay2_ej);
 
        tp_features.bay_status = bay_handle &&
                acpi_evalf(bay_handle, NULL, "_STA", "qv");
@@ -2474,7 +3422,7 @@ static int __init cmos_init(struct ibm_init_struct *iibm)
        vdbg_printk(TPACPI_DBG_INIT,
                "initializing cmos commands subdriver\n");
 
-       IBM_ACPIHANDLE_INIT(cmos);
+       TPACPI_ACPIHANDLE_INIT(cmos);
 
        vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
                str_supported(cmos_handle != NULL));
@@ -2538,10 +3486,24 @@ static struct ibm_struct cmos_driver_data = {
  * LED subdriver
  */
 
+enum led_access_mode {
+       TPACPI_LED_NONE = 0,
+       TPACPI_LED_570, /* 570 */
+       TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+       TPACPI_LED_NEW, /* all others */
+};
+
+enum { /* For TPACPI_LED_OLD */
+       TPACPI_LED_EC_HLCL = 0x0c,      /* EC reg to get led to power on */
+       TPACPI_LED_EC_HLBL = 0x0d,      /* EC reg to blink a lit led */
+       TPACPI_LED_EC_HLMS = 0x0e,      /* EC reg to select led to command */
+};
+
 static enum led_access_mode led_supported;
 
-IBM_HANDLE(led, ec, "SLED",    /* 570 */
-          "SYSL",              /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+TPACPI_HANDLE(led, ec, "SLED", /* 570 */
+          "SYSL",              /* 600e/x, 770e, 770x, A21e, A2xm/p, */
+                               /* T20-22, X20-21 */
           "LED",               /* all others */
           );                   /* R30, R31 */
 
@@ -2549,7 +3511,7 @@ static int __init led_init(struct ibm_init_struct *iibm)
 {
        vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
 
-       IBM_ACPIHANDLE_INIT(led);
+       TPACPI_ACPIHANDLE_INIT(led);
 
        if (!led_handle)
                /* led not supported on R30, R31 */
@@ -2638,13 +3600,11 @@ static int led_write(char *buf)
                        led = 1 << led;
                        ret = ec_write(TPACPI_LED_EC_HLMS, led);
                        if (ret >= 0)
-                               ret =
-                                   ec_write(TPACPI_LED_EC_HLBL,
-                                            led * led_exp_hlbl[ind]);
+                               ret = ec_write(TPACPI_LED_EC_HLBL,
+                                               led * led_exp_hlbl[ind]);
                        if (ret >= 0)
-                               ret =
-                                   ec_write(TPACPI_LED_EC_HLCL,
-                                            led * led_exp_hlcl[ind]);
+                               ret = ec_write(TPACPI_LED_EC_HLCL,
+                                               led * led_exp_hlcl[ind]);
                        if (ret < 0)
                                return ret;
                } else {
@@ -2668,13 +3628,13 @@ static struct ibm_struct led_driver_data = {
  * Beep subdriver
  */
 
-IBM_HANDLE(beep, ec, "BEEP");  /* all except R30, R31 */
+TPACPI_HANDLE(beep, ec, "BEEP");       /* all except R30, R31 */
 
 static int __init beep_init(struct ibm_init_struct *iibm)
 {
        vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
 
-       IBM_ACPIHANDLE_INIT(beep);
+       TPACPI_ACPIHANDLE_INIT(beep);
 
        vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
                str_supported(beep_handle != NULL));
@@ -2727,90 +3687,192 @@ static struct ibm_struct beep_driver_data = {
  * Thermal subdriver
  */
 
-static enum thermal_access_mode thermal_read_mode;
-
-/* sysfs temp##_input -------------------------------------------------- */
-
-static ssize_t thermal_temp_input_show(struct device *dev,
-                          struct device_attribute *attr,
-                          char *buf)
-{
-       struct sensor_device_attribute *sensor_attr =
-                                       to_sensor_dev_attr(attr);
-       int idx = sensor_attr->index;
-       s32 value;
-       int res;
-
-       res = thermal_get_sensor(idx, &value);
-       if (res)
-               return res;
-       if (value == TP_EC_THERMAL_TMP_NA * 1000)
-               return -ENXIO;
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", value);
-}
-
-#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
-        SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB)
-
-static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
-       THERMAL_SENSOR_ATTR_TEMP(1, 0),
-       THERMAL_SENSOR_ATTR_TEMP(2, 1),
-       THERMAL_SENSOR_ATTR_TEMP(3, 2),
-       THERMAL_SENSOR_ATTR_TEMP(4, 3),
-       THERMAL_SENSOR_ATTR_TEMP(5, 4),
-       THERMAL_SENSOR_ATTR_TEMP(6, 5),
-       THERMAL_SENSOR_ATTR_TEMP(7, 6),
-       THERMAL_SENSOR_ATTR_TEMP(8, 7),
-       THERMAL_SENSOR_ATTR_TEMP(9, 8),
-       THERMAL_SENSOR_ATTR_TEMP(10, 9),
-       THERMAL_SENSOR_ATTR_TEMP(11, 10),
-       THERMAL_SENSOR_ATTR_TEMP(12, 11),
-       THERMAL_SENSOR_ATTR_TEMP(13, 12),
-       THERMAL_SENSOR_ATTR_TEMP(14, 13),
-       THERMAL_SENSOR_ATTR_TEMP(15, 14),
-       THERMAL_SENSOR_ATTR_TEMP(16, 15),
-};
-
-#define THERMAL_ATTRS(X) \
-       &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr
-
-static struct attribute *thermal_temp_input_attr[] = {
-       THERMAL_ATTRS(8),
-       THERMAL_ATTRS(9),
-       THERMAL_ATTRS(10),
-       THERMAL_ATTRS(11),
-       THERMAL_ATTRS(12),
-       THERMAL_ATTRS(13),
-       THERMAL_ATTRS(14),
-       THERMAL_ATTRS(15),
-       THERMAL_ATTRS(0),
-       THERMAL_ATTRS(1),
-       THERMAL_ATTRS(2),
-       THERMAL_ATTRS(3),
-       THERMAL_ATTRS(4),
-       THERMAL_ATTRS(5),
-       THERMAL_ATTRS(6),
-       THERMAL_ATTRS(7),
-       NULL
+enum thermal_access_mode {
+       TPACPI_THERMAL_NONE = 0,        /* No thermal support */
+       TPACPI_THERMAL_ACPI_TMP07,      /* Use ACPI TMP0-7 */
+       TPACPI_THERMAL_ACPI_UPDT,       /* Use ACPI TMP0-7 with UPDT */
+       TPACPI_THERMAL_TPEC_8,          /* Use ACPI EC regs, 8 sensors */
+       TPACPI_THERMAL_TPEC_16,         /* Use ACPI EC regs, 16 sensors */
 };
 
-static const struct attribute_group thermal_temp_input16_group = {
-       .attrs = thermal_temp_input_attr
+enum { /* TPACPI_THERMAL_TPEC_* */
+       TP_EC_THERMAL_TMP0 = 0x78,      /* ACPI EC regs TMP 0..7 */
+       TP_EC_THERMAL_TMP8 = 0xC0,      /* ACPI EC regs TMP 8..15 */
+       TP_EC_THERMAL_TMP_NA = -128,    /* ACPI EC sensor not available */
 };
 
-static const struct attribute_group thermal_temp_input8_group = {
-       .attrs = &thermal_temp_input_attr[8]
+#define TPACPI_MAX_THERMAL_SENSORS 16  /* Max thermal sensors supported */
+struct ibm_thermal_sensors_struct {
+       s32 temp[TPACPI_MAX_THERMAL_SENSORS];
 };
 
-#undef THERMAL_SENSOR_ATTR_TEMP
-#undef THERMAL_ATTRS
-
-/* --------------------------------------------------------------------- */
+static enum thermal_access_mode thermal_read_mode;
 
-static int __init thermal_init(struct ibm_init_struct *iibm)
+/* idx is zero-based */
+static int thermal_get_sensor(int idx, s32 *value)
 {
-       u8 t, ta1, ta2;
+       int t;
+       s8 tmp;
+       char tmpi[5];
+
+       t = TP_EC_THERMAL_TMP0;
+
+       switch (thermal_read_mode) {
+#if TPACPI_MAX_THERMAL_SENSORS >= 16
+       case TPACPI_THERMAL_TPEC_16:
+               if (idx >= 8 && idx <= 15) {
+                       t = TP_EC_THERMAL_TMP8;
+                       idx -= 8;
+               }
+               /* fallthrough */
+#endif
+       case TPACPI_THERMAL_TPEC_8:
+               if (idx <= 7) {
+                       if (!acpi_ec_read(t + idx, &tmp))
+                               return -EIO;
+                       *value = tmp * 1000;
+                       return 0;
+               }
+               break;
+
+       case TPACPI_THERMAL_ACPI_UPDT:
+               if (idx <= 7) {
+                       snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+                       if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+                               return -EIO;
+                       if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+                               return -EIO;
+                       *value = (t - 2732) * 100;
+                       return 0;
+               }
+               break;
+
+       case TPACPI_THERMAL_ACPI_TMP07:
+               if (idx <= 7) {
+                       snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+                       if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+                               return -EIO;
+                       if (t > 127 || t < -127)
+                               t = TP_EC_THERMAL_TMP_NA;
+                       *value = t * 1000;
+                       return 0;
+               }
+               break;
+
+       case TPACPI_THERMAL_NONE:
+       default:
+               return -ENOSYS;
+       }
+
+       return -EINVAL;
+}
+
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
+{
+       int res, i;
+       int n;
+
+       n = 8;
+       i = 0;
+
+       if (!s)
+               return -EINVAL;
+
+       if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
+               n = 16;
+
+       for (i = 0 ; i < n; i++) {
+               res = thermal_get_sensor(i, &s->temp[i]);
+               if (res)
+                       return res;
+       }
+
+       return n;
+}
+
+/* sysfs temp##_input -------------------------------------------------- */
+
+static ssize_t thermal_temp_input_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct sensor_device_attribute *sensor_attr =
+                                       to_sensor_dev_attr(attr);
+       int idx = sensor_attr->index;
+       s32 value;
+       int res;
+
+       res = thermal_get_sensor(idx, &value);
+       if (res)
+               return res;
+       if (value == TP_EC_THERMAL_TMP_NA * 1000)
+               return -ENXIO;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
+        SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, \
+                    thermal_temp_input_show, NULL, _idxB)
+
+static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
+       THERMAL_SENSOR_ATTR_TEMP(1, 0),
+       THERMAL_SENSOR_ATTR_TEMP(2, 1),
+       THERMAL_SENSOR_ATTR_TEMP(3, 2),
+       THERMAL_SENSOR_ATTR_TEMP(4, 3),
+       THERMAL_SENSOR_ATTR_TEMP(5, 4),
+       THERMAL_SENSOR_ATTR_TEMP(6, 5),
+       THERMAL_SENSOR_ATTR_TEMP(7, 6),
+       THERMAL_SENSOR_ATTR_TEMP(8, 7),
+       THERMAL_SENSOR_ATTR_TEMP(9, 8),
+       THERMAL_SENSOR_ATTR_TEMP(10, 9),
+       THERMAL_SENSOR_ATTR_TEMP(11, 10),
+       THERMAL_SENSOR_ATTR_TEMP(12, 11),
+       THERMAL_SENSOR_ATTR_TEMP(13, 12),
+       THERMAL_SENSOR_ATTR_TEMP(14, 13),
+       THERMAL_SENSOR_ATTR_TEMP(15, 14),
+       THERMAL_SENSOR_ATTR_TEMP(16, 15),
+};
+
+#define THERMAL_ATTRS(X) \
+       &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr
+
+static struct attribute *thermal_temp_input_attr[] = {
+       THERMAL_ATTRS(8),
+       THERMAL_ATTRS(9),
+       THERMAL_ATTRS(10),
+       THERMAL_ATTRS(11),
+       THERMAL_ATTRS(12),
+       THERMAL_ATTRS(13),
+       THERMAL_ATTRS(14),
+       THERMAL_ATTRS(15),
+       THERMAL_ATTRS(0),
+       THERMAL_ATTRS(1),
+       THERMAL_ATTRS(2),
+       THERMAL_ATTRS(3),
+       THERMAL_ATTRS(4),
+       THERMAL_ATTRS(5),
+       THERMAL_ATTRS(6),
+       THERMAL_ATTRS(7),
+       NULL
+};
+
+static const struct attribute_group thermal_temp_input16_group = {
+       .attrs = thermal_temp_input_attr
+};
+
+static const struct attribute_group thermal_temp_input8_group = {
+       .attrs = &thermal_temp_input_attr[8]
+};
+
+#undef THERMAL_SENSOR_ATTR_TEMP
+#undef THERMAL_ATTRS
+
+/* --------------------------------------------------------------------- */
+
+static int __init thermal_init(struct ibm_init_struct *iibm)
+{
+       u8 t, ta1, ta2;
        int i;
        int acpi_tmp7;
        int res;
@@ -2845,12 +3907,13 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
                if (ta1 == 0) {
                        /* This is sheer paranoia, but we handle it anyway */
                        if (acpi_tmp7) {
-                               printk(IBM_ERR
+                               printk(TPACPI_ERR
                                       "ThinkPad ACPI EC access misbehaving, "
-                                      "falling back to ACPI TMPx access mode\n");
+                                      "falling back to ACPI TMPx access "
+                                      "mode\n");
                                thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
                        } else {
-                               printk(IBM_ERR
+                               printk(TPACPI_ERR
                                       "ThinkPad ACPI EC access misbehaving, "
                                       "disabling thermal sensors access\n");
                                thermal_read_mode = TPACPI_THERMAL_NONE;
@@ -2877,7 +3940,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
                str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
                thermal_read_mode);
 
-       switch(thermal_read_mode) {
+       switch (thermal_read_mode) {
        case TPACPI_THERMAL_TPEC_16:
                res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
                                &thermal_temp_input16_group);
@@ -2902,7 +3965,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
 
 static void thermal_exit(void)
 {
-       switch(thermal_read_mode) {
+       switch (thermal_read_mode) {
        case TPACPI_THERMAL_TPEC_16:
                sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
                                   &thermal_temp_input16_group);
@@ -2919,88 +3982,6 @@ static void thermal_exit(void)
        }
 }
 
-/* idx is zero-based */
-static int thermal_get_sensor(int idx, s32 *value)
-{
-       int t;
-       s8 tmp;
-       char tmpi[5];
-
-       t = TP_EC_THERMAL_TMP0;
-
-       switch (thermal_read_mode) {
-#if TPACPI_MAX_THERMAL_SENSORS >= 16
-       case TPACPI_THERMAL_TPEC_16:
-               if (idx >= 8 && idx <= 15) {
-                       t = TP_EC_THERMAL_TMP8;
-                       idx -= 8;
-               }
-               /* fallthrough */
-#endif
-       case TPACPI_THERMAL_TPEC_8:
-               if (idx <= 7) {
-                       if (!acpi_ec_read(t + idx, &tmp))
-                               return -EIO;
-                       *value = tmp * 1000;
-                       return 0;
-               }
-               break;
-
-       case TPACPI_THERMAL_ACPI_UPDT:
-               if (idx <= 7) {
-                       snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
-                       if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
-                               return -EIO;
-                       if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
-                               return -EIO;
-                       *value = (t - 2732) * 100;
-                       return 0;
-               }
-               break;
-
-       case TPACPI_THERMAL_ACPI_TMP07:
-               if (idx <= 7) {
-                       snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
-                       if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
-                               return -EIO;
-                       if (t > 127 || t < -127)
-                               t = TP_EC_THERMAL_TMP_NA;
-                       *value = t * 1000;
-                       return 0;
-               }
-               break;
-
-       case TPACPI_THERMAL_NONE:
-       default:
-               return -ENOSYS;
-       }
-
-       return -EINVAL;
-}
-
-static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
-{
-       int res, i;
-       int n;
-
-       n = 8;
-       i = 0;
-
-       if (!s)
-               return -EINVAL;
-
-       if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
-               n = 16;
-
-       for(i = 0 ; i < n; i++) {
-               res = thermal_get_sensor(i, &s->temp[i]);
-               if (res)
-                       return res;
-       }
-
-       return n;
-}
-
 static int thermal_read(char *p)
 {
        int len = 0;
@@ -3103,26 +4084,122 @@ static struct ibm_struct ecdump_driver_data = {
  * Backlight/brightness subdriver
  */
 
-static struct backlight_device *ibm_backlight_device;
+#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
 
-static struct backlight_ops ibm_backlight_data = {
-        .get_brightness = brightness_get,
-        .update_status  = brightness_update_status,
-};
+static struct backlight_device *ibm_backlight_device;
+static int brightness_offset = 0x31;
+static int brightness_mode;
+static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
 
 static struct mutex brightness_mutex;
 
-static int __init tpacpi_query_bcll_levels(acpi_handle handle)
+/*
+ * ThinkPads can read brightness from two places: EC 0x31, or
+ * CMOS NVRAM byte 0x5E, bits 0-3.
+ */
+static int brightness_get(struct backlight_device *bd)
 {
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       union acpi_object *obj;
+       u8 lec = 0, lcmos = 0, level = 0;
+
+       if (brightness_mode & 1) {
+               if (!acpi_ec_read(brightness_offset, &lec))
+                       return -EIO;
+               lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
+               level = lec;
+       };
+       if (brightness_mode & 2) {
+               lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
+                        & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+                       >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+               lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
+               level = lcmos;
+       }
+
+       if (brightness_mode == 3 && lec != lcmos) {
+               printk(TPACPI_ERR
+                       "CMOS NVRAM (%u) and EC (%u) do not agree "
+                       "on display brightness level\n",
+                       (unsigned int) lcmos,
+                       (unsigned int) lec);
+               return -EIO;
+       }
+
+       return level;
+}
+
+/* May return EINTR which can always be mapped to ERESTARTSYS */
+static int brightness_set(int value)
+{
+       int cmos_cmd, inc, i, res;
+       int current_value;
+
+       if (value > ((tp_features.bright_16levels)? 15 : 7))
+               return -EINVAL;
+
+       res = mutex_lock_interruptible(&brightness_mutex);
+       if (res < 0)
+               return res;
+
+       current_value = brightness_get(NULL);
+       if (current_value < 0) {
+               res = current_value;
+               goto errout;
+       }
+
+       cmos_cmd = value > current_value ?
+                       TP_CMOS_BRIGHTNESS_UP :
+                       TP_CMOS_BRIGHTNESS_DOWN;
+       inc = (value > current_value)? 1 : -1;
+
+       res = 0;
+       for (i = current_value; i != value; i += inc) {
+               if ((brightness_mode & 2) &&
+                   issue_thinkpad_cmos_command(cmos_cmd)) {
+                       res = -EIO;
+                       goto errout;
+               }
+               if ((brightness_mode & 1) &&
+                   !acpi_ec_write(brightness_offset, i + inc)) {
+                       res = -EIO;
+                       goto errout;;
+               }
+       }
+
+errout:
+       mutex_unlock(&brightness_mutex);
+       return res;
+}
+
+/* sysfs backlight class ----------------------------------------------- */
+
+static int brightness_update_status(struct backlight_device *bd)
+{
+       /* it is the backlight class's job (caller) to handle
+        * EINTR and other errors properly */
+       return brightness_set(
+               (bd->props.fb_blank == FB_BLANK_UNBLANK &&
+                bd->props.power == FB_BLANK_UNBLANK) ?
+                               bd->props.brightness : 0);
+}
+
+static struct backlight_ops ibm_backlight_data = {
+       .get_brightness = brightness_get,
+       .update_status  = brightness_update_status,
+};
+
+/* --------------------------------------------------------------------- */
+
+static int __init tpacpi_query_bcll_levels(acpi_handle handle)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
        int rc;
 
        if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
                obj = (union acpi_object *)buffer.pointer;
                if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
-                       printk(IBM_ERR "Unknown BCLL data, "
-                              "please report this to %s\n", IBM_MAIL);
+                       printk(TPACPI_ERR "Unknown BCLL data, "
+                              "please report this to %s\n", TPACPI_MAIL);
                        rc = 0;
                } else {
                        rc = obj->package.count;
@@ -3160,14 +4237,15 @@ static int __init brightness_check_levels(void)
        void *found_node = NULL;
 
        if (!vid_handle) {
-               IBM_ACPIHANDLE_INIT(vid);
+               TPACPI_ACPIHANDLE_INIT(vid);
        }
        if (!vid_handle)
                return 0;
 
        /* Search for a BCLL package with 16 levels */
        status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
-                                       brightness_find_bcll, NULL, &found_node);
+                                       brightness_find_bcll, NULL,
+                                       &found_node);
 
        return (ACPI_SUCCESS(status) && found_node != NULL);
 }
@@ -3193,14 +4271,14 @@ static int __init brightness_check_std_acpi_support(void)
        void *found_node = NULL;
 
        if (!vid_handle) {
-               IBM_ACPIHANDLE_INIT(vid);
+               TPACPI_ACPIHANDLE_INIT(vid);
        }
        if (!vid_handle)
                return 0;
 
        /* Search for a _BCL method, but don't execute it */
        status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
-                                    brightness_find_bcl, NULL, &found_node);
+                                    brightness_find_bcl, NULL, &found_node);
 
        return (ACPI_SUCCESS(status) && found_node != NULL);
 }
@@ -3215,12 +4293,14 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 
        if (!brightness_enable) {
                dbg_printk(TPACPI_DBG_INIT,
-                          "brightness support disabled by module parameter\n");
+                          "brightness support disabled by "
+                          "module parameter\n");
                return 1;
        } else if (brightness_enable > 1) {
                if (brightness_check_std_acpi_support()) {
-                       printk(IBM_NOTICE
-                              "standard ACPI backlight interface available, not loading native one...\n");
+                       printk(TPACPI_NOTICE
+                              "standard ACPI backlight interface "
+                              "available, not loading native one...\n");
                        return 1;
                }
        }
@@ -3247,13 +4327,14 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
                return 1;
 
        if (tp_features.bright_16levels)
-               printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n");
+               printk(TPACPI_INFO
+                      "detected a 16-level brightness capable ThinkPad\n");
 
        ibm_backlight_device = backlight_device_register(
                                        TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
                                        &ibm_backlight_data);
        if (IS_ERR(ibm_backlight_device)) {
-               printk(IBM_ERR "Could not register backlight device\n");
+               printk(TPACPI_ERR "Could not register backlight device\n");
                return PTR_ERR(ibm_backlight_device);
        }
        vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
@@ -3276,99 +4357,13 @@ static void brightness_exit(void)
        }
 }
 
-static int brightness_update_status(struct backlight_device *bd)
-{
-       /* it is the backlight class's job (caller) to handle
-        * EINTR and other errors properly */
-       return brightness_set(
-               (bd->props.fb_blank == FB_BLANK_UNBLANK &&
-                bd->props.power == FB_BLANK_UNBLANK) ?
-                               bd->props.brightness : 0);
-}
-
-/*
- * ThinkPads can read brightness from two places: EC 0x31, or
- * CMOS NVRAM byte 0x5E, bits 0-3.
- */
-static int brightness_get(struct backlight_device *bd)
-{
-       u8 lec = 0, lcmos = 0, level = 0;
-
-       if (brightness_mode & 1) {
-               if (!acpi_ec_read(brightness_offset, &lec))
-                       return -EIO;
-               lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
-               level = lec;
-       };
-       if (brightness_mode & 2) {
-               lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
-                        & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
-                       >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
-               lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
-               level = lcmos;
-       }
-
-       if (brightness_mode == 3 && lec != lcmos) {
-               printk(IBM_ERR
-                       "CMOS NVRAM (%u) and EC (%u) do not agree "
-                       "on display brightness level\n",
-                       (unsigned int) lcmos,
-                       (unsigned int) lec);
-               return -EIO;
-       }
-
-       return level;
-}
-
-/* May return EINTR which can always be mapped to ERESTARTSYS */
-static int brightness_set(int value)
-{
-       int cmos_cmd, inc, i, res;
-       int current_value;
-
-       if (value > ((tp_features.bright_16levels)? 15 : 7))
-               return -EINVAL;
-
-       res = mutex_lock_interruptible(&brightness_mutex);
-       if (res < 0)
-               return res;
-
-       current_value = brightness_get(NULL);
-       if (current_value < 0) {
-               res = current_value;
-               goto errout;
-       }
-
-       cmos_cmd = value > current_value ?
-                       TP_CMOS_BRIGHTNESS_UP :
-                       TP_CMOS_BRIGHTNESS_DOWN;
-       inc = (value > current_value)? 1 : -1;
-
-       res = 0;
-       for (i = current_value; i != value; i += inc) {
-               if ((brightness_mode & 2) &&
-                   issue_thinkpad_cmos_command(cmos_cmd)) {
-                       res = -EIO;
-                       goto errout;
-               }
-               if ((brightness_mode & 1) &&
-                   !acpi_ec_write(brightness_offset, i + inc)) {
-                       res = -EIO;
-                       goto errout;;
-               }
-       }
-
-errout:
-       mutex_unlock(&brightness_mutex);
-       return res;
-}
-
 static int brightness_read(char *p)
 {
        int len = 0;
        int level;
 
-       if ((level = brightness_get(NULL)) < 0) {
+       level = brightness_get(NULL);
+       if (level < 0) {
                len += sprintf(p + len, "level:\t\tunreadable\n");
        } else {
                len += sprintf(p + len, "level:\t\t%d\n", level);
@@ -3425,6 +4420,8 @@ static struct ibm_struct brightness_driver_data = {
  * Volume subdriver
  */
 
+static int volume_offset = 0x30;
+
 static int volume_read(char *p)
 {
        int len = 0;
@@ -3474,8 +4471,11 @@ static int volume_write(char *buf)
                } else
                        return -EINVAL;
 
-               if (new_level != level) {       /* mute doesn't change */
-                       cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
+               if (new_level != level) {
+                       /* mute doesn't change */
+
+                       cmos_cmd = (new_level > level) ?
+                                       TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
                        inc = new_level > level ? 1 : -1;
 
                        if (mute && (issue_thinkpad_cmos_command(cmos_cmd) ||
@@ -3487,14 +4487,18 @@ static int volume_write(char *buf)
                                    !acpi_ec_write(volume_offset, i + inc))
                                        return -EIO;
 
-                       if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
-                                    !acpi_ec_write(volume_offset,
-                                                   new_level + mute)))
+                       if (mute &&
+                           (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
+                            !acpi_ec_write(volume_offset, new_level + mute))) {
                                return -EIO;
+                       }
                }
 
-               if (new_mute != mute) { /* level doesn't change */
-                       cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
+               if (new_mute != mute) {
+                       /* level doesn't change */
+
+                       cmos_cmd = (new_mute) ?
+                                  TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
 
                        if (issue_thinkpad_cmos_command(cmos_cmd) ||
                            !acpi_ec_write(volume_offset, level + new_mute))
@@ -3616,478 +4620,333 @@ static struct ibm_struct volume_driver_data = {
  *     but the ACPI tables just mention level 7.
  */
 
+enum {                                 /* Fan control constants */
+       fan_status_offset = 0x2f,       /* EC register 0x2f */
+       fan_rpm_offset = 0x84,          /* EC register 0x84: LSB, 0x85 MSB (RPM)
+                                        * 0x84 must be read before 0x85 */
+
+       TP_EC_FAN_FULLSPEED = 0x40,     /* EC fan mode: full speed */
+       TP_EC_FAN_AUTO      = 0x80,     /* EC fan mode: auto fan control */
+
+       TPACPI_FAN_LAST_LEVEL = 0x100,  /* Use cached last-seen fan level */
+};
+
+enum fan_status_access_mode {
+       TPACPI_FAN_NONE = 0,            /* No fan status or control */
+       TPACPI_FAN_RD_ACPI_GFAN,        /* Use ACPI GFAN */
+       TPACPI_FAN_RD_TPEC,             /* Use ACPI EC regs 0x2f, 0x84-0x85 */
+};
+
+enum fan_control_access_mode {
+       TPACPI_FAN_WR_NONE = 0,         /* No fan control */
+       TPACPI_FAN_WR_ACPI_SFAN,        /* Use ACPI SFAN */
+       TPACPI_FAN_WR_TPEC,             /* Use ACPI EC reg 0x2f */
+       TPACPI_FAN_WR_ACPI_FANS,        /* Use ACPI FANS and EC reg 0x2f */
+};
+
+enum fan_control_commands {
+       TPACPI_FAN_CMD_SPEED    = 0x0001,       /* speed command */
+       TPACPI_FAN_CMD_LEVEL    = 0x0002,       /* level command  */
+       TPACPI_FAN_CMD_ENABLE   = 0x0004,       /* enable/disable cmd,
+                                                * and also watchdog cmd */
+};
+
+static int fan_control_allowed;
+
 static enum fan_status_access_mode fan_status_access_mode;
 static enum fan_control_access_mode fan_control_access_mode;
 static enum fan_control_commands fan_control_commands;
 
 static u8 fan_control_initial_status;
 static u8 fan_control_desired_level;
+static int fan_watchdog_maxinterval;
+
+static struct mutex fan_mutex;
 
 static void fan_watchdog_fire(struct work_struct *ignored);
-static int fan_watchdog_maxinterval;
 static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
 
-IBM_HANDLE(fans, ec, "FANS");  /* X31, X40, X41 */
-IBM_HANDLE(gfan, ec, "GFAN",   /* 570 */
+TPACPI_HANDLE(fans, ec, "FANS");       /* X31, X40, X41 */
+TPACPI_HANDLE(gfan, ec, "GFAN",        /* 570 */
           "\\FSPD",            /* 600e/x, 770e, 770x */
           );                   /* all others */
-IBM_HANDLE(sfan, ec, "SFAN",   /* 570 */
+TPACPI_HANDLE(sfan, ec, "SFAN",        /* 570 */
           "JFNS",              /* 770x-JL */
           );                   /* all others */
 
 /*
- * SYSFS fan layout: hwmon compatible (device)
- *
- * pwm*_enable:
- *     0: "disengaged" mode
- *     1: manual mode
- *     2: native EC "auto" mode (recommended, hardware default)
- *
- * pwm*: set speed in manual mode, ignored otherwise.
- *     0 is level 0; 255 is level 7. Intermediate points done with linear
- *     interpolation.
- *
- * fan*_input: tachometer reading, RPM
- *
- *
- * SYSFS fan layout: extensions
- *
- * fan_watchdog (driver):
- *     fan watchdog interval in seconds, 0 disables (default), max 120
+ * Call with fan_mutex held
  */
-
-/* sysfs fan pwm1_enable ----------------------------------------------- */
-static ssize_t fan_pwm1_enable_show(struct device *dev,
-                                   struct device_attribute *attr,
-                                   char *buf)
+static void fan_update_desired_level(u8 status)
 {
-       int res, mode;
-       u8 status;
-
-       res = fan_get_status_safe(&status);
-       if (res)
-               return res;
-
-       if (unlikely(tp_features.fan_ctrl_status_undef)) {
-               if (status != fan_control_initial_status) {
-                       tp_features.fan_ctrl_status_undef = 0;
-               } else {
-                       /* Return most likely status. In fact, it
-                        * might be the only possible status */
-                       status = TP_EC_FAN_AUTO;
-               }
+       if ((status &
+            (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+               if (status > 7)
+                       fan_control_desired_level = 7;
+               else
+                       fan_control_desired_level = status;
        }
-
-       if (status & TP_EC_FAN_FULLSPEED) {
-               mode = 0;
-       } else if (status & TP_EC_FAN_AUTO) {
-               mode = 2;
-       } else
-               mode = 1;
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", mode);
 }
 
-static ssize_t fan_pwm1_enable_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t count)
+static int fan_get_status(u8 *status)
 {
-       unsigned long t;
-       int res, level;
+       u8 s;
 
-       if (parse_strtoul(buf, 2, &t))
-               return -EINVAL;
+       /* TODO:
+        * Add TPACPI_FAN_RD_ACPI_FANS ? */
 
-       switch (t) {
-       case 0:
-               level = TP_EC_FAN_FULLSPEED;
-               break;
-       case 1:
-               level = TPACPI_FAN_LAST_LEVEL;
-               break;
-       case 2:
-               level = TP_EC_FAN_AUTO;
-               break;
-       case 3:
-               /* reserved for software-controlled auto mode */
-               return -ENOSYS;
-       default:
-               return -EINVAL;
-       }
+       switch (fan_status_access_mode) {
+       case TPACPI_FAN_RD_ACPI_GFAN:
+               /* 570, 600e/x, 770e, 770x */
 
-       res = fan_set_level_safe(level);
-       if (res == -ENXIO)
-               return -EINVAL;
-       else if (res < 0)
-               return res;
+               if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+                       return -EIO;
 
-       fan_watchdog_reset();
+               if (likely(status))
+                       *status = s & 0x07;
 
-       return count;
-}
+               break;
 
-static struct device_attribute dev_attr_fan_pwm1_enable =
-       __ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
-               fan_pwm1_enable_show, fan_pwm1_enable_store);
+       case TPACPI_FAN_RD_TPEC:
+               /* all except 570, 600e/x, 770e, 770x */
+               if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
+                       return -EIO;
 
-/* sysfs fan pwm1 ------------------------------------------------------ */
-static ssize_t fan_pwm1_show(struct device *dev,
-                            struct device_attribute *attr,
-                            char *buf)
-{
-       int res;
-       u8 status;
+               if (likely(status))
+                       *status = s;
 
-       res = fan_get_status_safe(&status);
-       if (res)
-               return res;
+               break;
 
-       if (unlikely(tp_features.fan_ctrl_status_undef)) {
-               if (status != fan_control_initial_status) {
-                       tp_features.fan_ctrl_status_undef = 0;
-               } else {
-                       status = TP_EC_FAN_AUTO;
-               }
+       default:
+               return -ENXIO;
        }
 
-       if ((status &
-            (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
-               status = fan_control_desired_level;
+       return 0;
+}
 
-       if (status > 7)
-               status = 7;
+static int fan_get_status_safe(u8 *status)
+{
+       int rc;
+       u8 s;
 
-       return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7);
+       if (mutex_lock_interruptible(&fan_mutex))
+               return -ERESTARTSYS;
+       rc = fan_get_status(&s);
+       if (!rc)
+               fan_update_desired_level(s);
+       mutex_unlock(&fan_mutex);
+
+       if (status)
+               *status = s;
+
+       return rc;
 }
 
-static ssize_t fan_pwm1_store(struct device *dev,
-                             struct device_attribute *attr,
-                             const char *buf, size_t count)
+static int fan_get_speed(unsigned int *speed)
 {
-       unsigned long s;
-       int rc;
-       u8 status, newlevel;
+       u8 hi, lo;
 
-       if (parse_strtoul(buf, 255, &s))
-               return -EINVAL;
+       switch (fan_status_access_mode) {
+       case TPACPI_FAN_RD_TPEC:
+               /* all except 570, 600e/x, 770e, 770x */
+               if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
+                            !acpi_ec_read(fan_rpm_offset + 1, &hi)))
+                       return -EIO;
 
-       /* scale down from 0-255 to 0-7 */
-       newlevel = (s >> 5) & 0x07;
+               if (likely(speed))
+                       *speed = (hi << 8) | lo;
 
-       if (mutex_lock_interruptible(&fan_mutex))
-               return -ERESTARTSYS;
+               break;
 
-       rc = fan_get_status(&status);
-       if (!rc && (status &
-                   (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
-               rc = fan_set_level(newlevel);
-               if (rc == -ENXIO)
-                       rc = -EINVAL;
-               else if (!rc) {
-                       fan_update_desired_level(newlevel);
-                       fan_watchdog_reset();
-               }
+       default:
+               return -ENXIO;
        }
 
-       mutex_unlock(&fan_mutex);
-       return (rc)? rc : count;
+       return 0;
 }
 
-static struct device_attribute dev_attr_fan_pwm1 =
-       __ATTR(pwm1, S_IWUSR | S_IRUGO,
-               fan_pwm1_show, fan_pwm1_store);
-
-/* sysfs fan fan1_input ------------------------------------------------ */
-static ssize_t fan_fan1_input_show(struct device *dev,
-                          struct device_attribute *attr,
-                          char *buf)
+static int fan_set_level(int level)
 {
-       int res;
-       unsigned int speed;
+       if (!fan_control_allowed)
+               return -EPERM;
 
-       res = fan_get_speed(&speed);
-       if (res < 0)
-               return res;
+       switch (fan_control_access_mode) {
+       case TPACPI_FAN_WR_ACPI_SFAN:
+               if (level >= 0 && level <= 7) {
+                       if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
+                               return -EIO;
+               } else
+                       return -EINVAL;
+               break;
 
-       return snprintf(buf, PAGE_SIZE, "%u\n", speed);
-}
+       case TPACPI_FAN_WR_ACPI_FANS:
+       case TPACPI_FAN_WR_TPEC:
+               if ((level != TP_EC_FAN_AUTO) &&
+                   (level != TP_EC_FAN_FULLSPEED) &&
+                   ((level < 0) || (level > 7)))
+                       return -EINVAL;
 
-static struct device_attribute dev_attr_fan_fan1_input =
-       __ATTR(fan1_input, S_IRUGO,
-               fan_fan1_input_show, NULL);
+               /* safety net should the EC not support AUTO
+                * or FULLSPEED mode bits and just ignore them */
+               if (level & TP_EC_FAN_FULLSPEED)
+                       level |= 7;     /* safety min speed 7 */
+               else if (level & TP_EC_FAN_AUTO)
+                       level |= 4;     /* safety min speed 4 */
 
-/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
-static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
-                                    char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
+               if (!acpi_ec_write(fan_status_offset, level))
+                       return -EIO;
+               else
+                       tp_features.fan_ctrl_status_undef = 0;
+               break;
+
+       default:
+               return -ENXIO;
+       }
+       return 0;
 }
 
-static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
-                                     const char *buf, size_t count)
+static int fan_set_level_safe(int level)
 {
-       unsigned long t;
-
-       if (parse_strtoul(buf, 120, &t))
-               return -EINVAL;
+       int rc;
 
        if (!fan_control_allowed)
                return -EPERM;
 
-       fan_watchdog_maxinterval = t;
-       fan_watchdog_reset();
-
-       return count;
-}
+       if (mutex_lock_interruptible(&fan_mutex))
+               return -ERESTARTSYS;
 
-static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
-               fan_fan_watchdog_show, fan_fan_watchdog_store);
+       if (level == TPACPI_FAN_LAST_LEVEL)
+               level = fan_control_desired_level;
 
-/* --------------------------------------------------------------------- */
-static struct attribute *fan_attributes[] = {
-       &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
-       &dev_attr_fan_fan1_input.attr,
-       NULL
-};
+       rc = fan_set_level(level);
+       if (!rc)
+               fan_update_desired_level(level);
 
-static const struct attribute_group fan_attr_group = {
-       .attrs = fan_attributes,
-};
+       mutex_unlock(&fan_mutex);
+       return rc;
+}
 
-static int __init fan_init(struct ibm_init_struct *iibm)
+static int fan_set_enable(void)
 {
+       u8 s;
        int rc;
 
-       vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
+       if (!fan_control_allowed)
+               return -EPERM;
 
-       mutex_init(&fan_mutex);
-       fan_status_access_mode = TPACPI_FAN_NONE;
-       fan_control_access_mode = TPACPI_FAN_WR_NONE;
-       fan_control_commands = 0;
-       fan_watchdog_maxinterval = 0;
-       tp_features.fan_ctrl_status_undef = 0;
-       fan_control_desired_level = 7;
+       if (mutex_lock_interruptible(&fan_mutex))
+               return -ERESTARTSYS;
 
-       IBM_ACPIHANDLE_INIT(fans);
-       IBM_ACPIHANDLE_INIT(gfan);
-       IBM_ACPIHANDLE_INIT(sfan);
+       switch (fan_control_access_mode) {
+       case TPACPI_FAN_WR_ACPI_FANS:
+       case TPACPI_FAN_WR_TPEC:
+               rc = fan_get_status(&s);
+               if (rc < 0)
+                       break;
 
-       if (gfan_handle) {
-               /* 570, 600e/x, 770e, 770x */
-               fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
-       } else {
-               /* all other ThinkPads: note that even old-style
-                * ThinkPad ECs supports the fan control register */
-               if (likely(acpi_ec_read(fan_status_offset,
-                                       &fan_control_initial_status))) {
-                       fan_status_access_mode = TPACPI_FAN_RD_TPEC;
+               /* Don't go out of emergency fan mode */
+               if (s != 7) {
+                       s &= 0x07;
+                       s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
+               }
 
-                       /* In some ThinkPads, neither the EC nor the ACPI
-                        * DSDT initialize the fan status, and it ends up
-                        * being set to 0x07 when it *could* be either
-                        * 0x07 or 0x80.
-                        *
-                        * Enable for TP-1Y (T43), TP-78 (R51e),
-                        * TP-76 (R52), TP-70 (T43, R52), which are known
-                        * to be buggy. */
-                       if (fan_control_initial_status == 0x07) {
-                               switch (thinkpad_id.ec_model) {
-                               case 0x5931: /* TP-1Y */
-                               case 0x3837: /* TP-78 */
-                               case 0x3637: /* TP-76 */
-                               case 0x3037: /* TP-70 */
-                                       printk(IBM_NOTICE
-                                              "fan_init: initial fan status is "
-                                              "unknown, assuming it is in auto "
-                                              "mode\n");
-                                       tp_features.fan_ctrl_status_undef = 1;
-                                       ;;
-                               }
-                       }
-               } else {
-                       printk(IBM_ERR
-                              "ThinkPad ACPI EC access misbehaving, "
-                              "fan status and control unavailable\n");
-                       return 1;
-               }
-       }
-
-       if (sfan_handle) {
-               /* 570, 770x-JL */
-               fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN;
-               fan_control_commands |=
-                   TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE;
-       } else {
-               if (!gfan_handle) {
-                       /* gfan without sfan means no fan control */
-                       /* all other models implement TP EC 0x2f control */
-
-                       if (fans_handle) {
-                               /* X31, X40, X41 */
-                               fan_control_access_mode =
-                                   TPACPI_FAN_WR_ACPI_FANS;
-                               fan_control_commands |=
-                                   TPACPI_FAN_CMD_SPEED |
-                                   TPACPI_FAN_CMD_LEVEL |
-                                   TPACPI_FAN_CMD_ENABLE;
-                       } else {
-                               fan_control_access_mode = TPACPI_FAN_WR_TPEC;
-                               fan_control_commands |=
-                                   TPACPI_FAN_CMD_LEVEL |
-                                   TPACPI_FAN_CMD_ENABLE;
-                       }
+               if (!acpi_ec_write(fan_status_offset, s))
+                       rc = -EIO;
+               else {
+                       tp_features.fan_ctrl_status_undef = 0;
+                       rc = 0;
                }
-       }
-
-       vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n",
-               str_supported(fan_status_access_mode != TPACPI_FAN_NONE ||
-                 fan_control_access_mode != TPACPI_FAN_WR_NONE),
-               fan_status_access_mode, fan_control_access_mode);
-
-       /* fan control master switch */
-       if (!fan_control_allowed) {
-               fan_control_access_mode = TPACPI_FAN_WR_NONE;
-               fan_control_commands = 0;
-               dbg_printk(TPACPI_DBG_INIT,
-                          "fan control features disabled by parameter\n");
-       }
-
-       /* update fan_control_desired_level */
-       if (fan_status_access_mode != TPACPI_FAN_NONE)
-               fan_get_status_safe(NULL);
+               break;
 
-       if (fan_status_access_mode != TPACPI_FAN_NONE ||
-           fan_control_access_mode != TPACPI_FAN_WR_NONE) {
-               rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
-                                        &fan_attr_group);
-               if (!(rc < 0))
-                       rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
-                                       &driver_attr_fan_watchdog);
+       case TPACPI_FAN_WR_ACPI_SFAN:
+               rc = fan_get_status(&s);
                if (rc < 0)
-                       return rc;
-               return 0;
-       } else
-               return 1;
-}
-
-/*
- * Call with fan_mutex held
- */
-static void fan_update_desired_level(u8 status)
-{
-       if ((status &
-            (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
-               if (status > 7)
-                       fan_control_desired_level = 7;
-               else
-                       fan_control_desired_level = status;
-       }
-}
-
-static int fan_get_status(u8 *status)
-{
-       u8 s;
-
-       /* TODO:
-        * Add TPACPI_FAN_RD_ACPI_FANS ? */
-
-       switch (fan_status_access_mode) {
-       case TPACPI_FAN_RD_ACPI_GFAN:
-               /* 570, 600e/x, 770e, 770x */
-
-               if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
-                       return -EIO;
-
-               if (likely(status))
-                       *status = s & 0x07;
-
-               break;
+                       break;
 
-       case TPACPI_FAN_RD_TPEC:
-               /* all except 570, 600e/x, 770e, 770x */
-               if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
-                       return -EIO;
+               s &= 0x07;
 
-               if (likely(status))
-                       *status = s;
+               /* Set fan to at least level 4 */
+               s |= 4;
 
+               if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
+                       rc = -EIO;
+               else
+                       rc = 0;
                break;
 
        default:
-               return -ENXIO;
+               rc = -ENXIO;
        }
 
-       return 0;
+       mutex_unlock(&fan_mutex);
+       return rc;
 }
 
-static int fan_get_status_safe(u8 *status)
+static int fan_set_disable(void)
 {
        int rc;
-       u8 s;
+
+       if (!fan_control_allowed)
+               return -EPERM;
 
        if (mutex_lock_interruptible(&fan_mutex))
                return -ERESTARTSYS;
-       rc = fan_get_status(&s);
-       if (!rc)
-               fan_update_desired_level(s);
-       mutex_unlock(&fan_mutex);
 
-       if (status)
-               *status = s;
+       rc = 0;
+       switch (fan_control_access_mode) {
+       case TPACPI_FAN_WR_ACPI_FANS:
+       case TPACPI_FAN_WR_TPEC:
+               if (!acpi_ec_write(fan_status_offset, 0x00))
+                       rc = -EIO;
+               else {
+                       fan_control_desired_level = 0;
+                       tp_features.fan_ctrl_status_undef = 0;
+               }
+               break;
 
-       return rc;
-}
+       case TPACPI_FAN_WR_ACPI_SFAN:
+               if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+                       rc = -EIO;
+               else
+                       fan_control_desired_level = 0;
+               break;
 
-static void fan_exit(void)
-{
-       vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
+       default:
+               rc = -ENXIO;
+       }
 
-       /* FIXME: can we really do this unconditionally? */
-       sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
-       driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog);
 
-       cancel_delayed_work(&fan_watchdog_task);
-       flush_scheduled_work();
+       mutex_unlock(&fan_mutex);
+       return rc;
 }
 
-static int fan_get_speed(unsigned int *speed)
+static int fan_set_speed(int speed)
 {
-       u8 hi, lo;
+       int rc;
 
-       switch (fan_status_access_mode) {
-       case TPACPI_FAN_RD_TPEC:
-               /* all except 570, 600e/x, 770e, 770x */
-               if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
-                            !acpi_ec_read(fan_rpm_offset + 1, &hi)))
-                       return -EIO;
+       if (!fan_control_allowed)
+               return -EPERM;
 
-               if (likely(speed))
-                       *speed = (hi << 8) | lo;
+       if (mutex_lock_interruptible(&fan_mutex))
+               return -ERESTARTSYS;
 
+       rc = 0;
+       switch (fan_control_access_mode) {
+       case TPACPI_FAN_WR_ACPI_FANS:
+               if (speed >= 0 && speed <= 65535) {
+                       if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
+                                       speed, speed, speed))
+                               rc = -EIO;
+               } else
+                       rc = -EINVAL;
                break;
 
        default:
-               return -ENXIO;
+               rc = -ENXIO;
        }
 
-       return 0;
-}
-
-static void fan_watchdog_fire(struct work_struct *ignored)
-{
-       int rc;
-
-       if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
-               return;
-
-       printk(IBM_NOTICE "fan watchdog: enabling fan\n");
-       rc = fan_set_enable();
-       if (rc < 0) {
-               printk(IBM_ERR "fan watchdog: error %d while enabling fan, "
-                       "will try again later...\n", -rc);
-               /* reschedule for later */
-               fan_watchdog_reset();
-       }
+       mutex_unlock(&fan_mutex);
+       return rc;
 }
 
 static void fan_watchdog_reset(void)
@@ -4106,195 +4965,378 @@ static void fan_watchdog_reset(void)
                if (!schedule_delayed_work(&fan_watchdog_task,
                                msecs_to_jiffies(fan_watchdog_maxinterval
                                                 * 1000))) {
-                       printk(IBM_ERR "failed to schedule the fan watchdog, "
+                       printk(TPACPI_ERR
+                              "failed to schedule the fan watchdog, "
                               "watchdog will not trigger\n");
                }
        } else
                fan_watchdog_active = 0;
 }
 
-static int fan_set_level(int level)
+static void fan_watchdog_fire(struct work_struct *ignored)
 {
-       if (!fan_control_allowed)
-               return -EPERM;
-
-       switch (fan_control_access_mode) {
-       case TPACPI_FAN_WR_ACPI_SFAN:
-               if (level >= 0 && level <= 7) {
-                       if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
-                               return -EIO;
-               } else
-                       return -EINVAL;
-               break;
+       int rc;
 
-       case TPACPI_FAN_WR_ACPI_FANS:
-       case TPACPI_FAN_WR_TPEC:
-               if ((level != TP_EC_FAN_AUTO) &&
-                   (level != TP_EC_FAN_FULLSPEED) &&
-                   ((level < 0) || (level > 7)))
-                       return -EINVAL;
+       if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+               return;
 
-               /* safety net should the EC not support AUTO
-                * or FULLSPEED mode bits and just ignore them */
-               if (level & TP_EC_FAN_FULLSPEED)
-                       level |= 7;     /* safety min speed 7 */
-               else if (level & TP_EC_FAN_FULLSPEED)
-                       level |= 4;     /* safety min speed 4 */
+       printk(TPACPI_NOTICE "fan watchdog: enabling fan\n");
+       rc = fan_set_enable();
+       if (rc < 0) {
+               printk(TPACPI_ERR "fan watchdog: error %d while enabling fan, "
+                       "will try again later...\n", -rc);
+               /* reschedule for later */
+               fan_watchdog_reset();
+       }
+}
 
-               if (!acpi_ec_write(fan_status_offset, level))
-                       return -EIO;
-               else
+/*
+ * SYSFS fan layout: hwmon compatible (device)
+ *
+ * pwm*_enable:
+ *     0: "disengaged" mode
+ *     1: manual mode
+ *     2: native EC "auto" mode (recommended, hardware default)
+ *
+ * pwm*: set speed in manual mode, ignored otherwise.
+ *     0 is level 0; 255 is level 7. Intermediate points done with linear
+ *     interpolation.
+ *
+ * fan*_input: tachometer reading, RPM
+ *
+ *
+ * SYSFS fan layout: extensions
+ *
+ * fan_watchdog (driver):
+ *     fan watchdog interval in seconds, 0 disables (default), max 120
+ */
+
+/* sysfs fan pwm1_enable ----------------------------------------------- */
+static ssize_t fan_pwm1_enable_show(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       int res, mode;
+       u8 status;
+
+       res = fan_get_status_safe(&status);
+       if (res)
+               return res;
+
+       if (unlikely(tp_features.fan_ctrl_status_undef)) {
+               if (status != fan_control_initial_status) {
                        tp_features.fan_ctrl_status_undef = 0;
-               break;
+               } else {
+                       /* Return most likely status. In fact, it
+                        * might be the only possible status */
+                       status = TP_EC_FAN_AUTO;
+               }
+       }
 
+       if (status & TP_EC_FAN_FULLSPEED) {
+               mode = 0;
+       } else if (status & TP_EC_FAN_AUTO) {
+               mode = 2;
+       } else
+               mode = 1;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", mode);
+}
+
+static ssize_t fan_pwm1_enable_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       unsigned long t;
+       int res, level;
+
+       if (parse_strtoul(buf, 2, &t))
+               return -EINVAL;
+
+       switch (t) {
+       case 0:
+               level = TP_EC_FAN_FULLSPEED;
+               break;
+       case 1:
+               level = TPACPI_FAN_LAST_LEVEL;
+               break;
+       case 2:
+               level = TP_EC_FAN_AUTO;
+               break;
+       case 3:
+               /* reserved for software-controlled auto mode */
+               return -ENOSYS;
        default:
-               return -ENXIO;
+               return -EINVAL;
        }
-       return 0;
+
+       res = fan_set_level_safe(level);
+       if (res == -ENXIO)
+               return -EINVAL;
+       else if (res < 0)
+               return res;
+
+       fan_watchdog_reset();
+
+       return count;
 }
 
-static int fan_set_level_safe(int level)
+static struct device_attribute dev_attr_fan_pwm1_enable =
+       __ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+               fan_pwm1_enable_show, fan_pwm1_enable_store);
+
+/* sysfs fan pwm1 ------------------------------------------------------ */
+static ssize_t fan_pwm1_show(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
 {
-       int rc;
+       int res;
+       u8 status;
 
-       if (!fan_control_allowed)
-               return -EPERM;
+       res = fan_get_status_safe(&status);
+       if (res)
+               return res;
 
-       if (mutex_lock_interruptible(&fan_mutex))
-               return -ERESTARTSYS;
+       if (unlikely(tp_features.fan_ctrl_status_undef)) {
+               if (status != fan_control_initial_status) {
+                       tp_features.fan_ctrl_status_undef = 0;
+               } else {
+                       status = TP_EC_FAN_AUTO;
+               }
+       }
 
-       if (level == TPACPI_FAN_LAST_LEVEL)
-               level = fan_control_desired_level;
+       if ((status &
+            (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
+               status = fan_control_desired_level;
 
-       rc = fan_set_level(level);
-       if (!rc)
-               fan_update_desired_level(level);
+       if (status > 7)
+               status = 7;
 
-       mutex_unlock(&fan_mutex);
-       return rc;
+       return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7);
 }
 
-static int fan_set_enable(void)
+static ssize_t fan_pwm1_store(struct device *dev,
+                             struct device_attribute *attr,
+                             const char *buf, size_t count)
 {
-       u8 s;
+       unsigned long s;
        int rc;
+       u8 status, newlevel;
 
-       if (!fan_control_allowed)
-               return -EPERM;
+       if (parse_strtoul(buf, 255, &s))
+               return -EINVAL;
+
+       /* scale down from 0-255 to 0-7 */
+       newlevel = (s >> 5) & 0x07;
 
        if (mutex_lock_interruptible(&fan_mutex))
                return -ERESTARTSYS;
 
-       switch (fan_control_access_mode) {
-       case TPACPI_FAN_WR_ACPI_FANS:
-       case TPACPI_FAN_WR_TPEC:
-               rc = fan_get_status(&s);
-               if (rc < 0)
-                       break;
-
-               /* Don't go out of emergency fan mode */
-               if (s != 7) {
-                       s &= 0x07;
-                       s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
+       rc = fan_get_status(&status);
+       if (!rc && (status &
+                   (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+               rc = fan_set_level(newlevel);
+               if (rc == -ENXIO)
+                       rc = -EINVAL;
+               else if (!rc) {
+                       fan_update_desired_level(newlevel);
+                       fan_watchdog_reset();
                }
+       }
 
-               if (!acpi_ec_write(fan_status_offset, s))
-                       rc = -EIO;
-               else {
-                       tp_features.fan_ctrl_status_undef = 0;
-                       rc = 0;
-               }
-               break;
+       mutex_unlock(&fan_mutex);
+       return (rc)? rc : count;
+}
 
-       case TPACPI_FAN_WR_ACPI_SFAN:
-               rc = fan_get_status(&s);
-               if (rc < 0)
-                       break;
+static struct device_attribute dev_attr_fan_pwm1 =
+       __ATTR(pwm1, S_IWUSR | S_IRUGO,
+               fan_pwm1_show, fan_pwm1_store);
 
-               s &= 0x07;
+/* sysfs fan fan1_input ------------------------------------------------ */
+static ssize_t fan_fan1_input_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int res;
+       unsigned int speed;
 
-               /* Set fan to at least level 4 */
-               s |= 4;
+       res = fan_get_speed(&speed);
+       if (res < 0)
+               return res;
 
-               if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
-                       rc= -EIO;
-               else
-                       rc = 0;
-               break;
+       return snprintf(buf, PAGE_SIZE, "%u\n", speed);
+}
 
-       default:
-               rc = -ENXIO;
-       }
+static struct device_attribute dev_attr_fan_fan1_input =
+       __ATTR(fan1_input, S_IRUGO,
+               fan_fan1_input_show, NULL);
 
-       mutex_unlock(&fan_mutex);
-       return rc;
+/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
+static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
+                                    char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
 }
 
-static int fan_set_disable(void)
+static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
+                                     const char *buf, size_t count)
 {
-       int rc;
+       unsigned long t;
+
+       if (parse_strtoul(buf, 120, &t))
+               return -EINVAL;
 
        if (!fan_control_allowed)
                return -EPERM;
 
-       if (mutex_lock_interruptible(&fan_mutex))
-               return -ERESTARTSYS;
+       fan_watchdog_maxinterval = t;
+       fan_watchdog_reset();
 
-       rc = 0;
-       switch (fan_control_access_mode) {
-       case TPACPI_FAN_WR_ACPI_FANS:
-       case TPACPI_FAN_WR_TPEC:
-               if (!acpi_ec_write(fan_status_offset, 0x00))
-                       rc = -EIO;
-               else {
-                       fan_control_desired_level = 0;
-                       tp_features.fan_ctrl_status_undef = 0;
+       return count;
+}
+
+static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
+               fan_fan_watchdog_show, fan_fan_watchdog_store);
+
+/* --------------------------------------------------------------------- */
+static struct attribute *fan_attributes[] = {
+       &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
+       &dev_attr_fan_fan1_input.attr,
+       NULL
+};
+
+static const struct attribute_group fan_attr_group = {
+       .attrs = fan_attributes,
+};
+
+static int __init fan_init(struct ibm_init_struct *iibm)
+{
+       int rc;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
+
+       mutex_init(&fan_mutex);
+       fan_status_access_mode = TPACPI_FAN_NONE;
+       fan_control_access_mode = TPACPI_FAN_WR_NONE;
+       fan_control_commands = 0;
+       fan_watchdog_maxinterval = 0;
+       tp_features.fan_ctrl_status_undef = 0;
+       fan_control_desired_level = 7;
+
+       TPACPI_ACPIHANDLE_INIT(fans);
+       TPACPI_ACPIHANDLE_INIT(gfan);
+       TPACPI_ACPIHANDLE_INIT(sfan);
+
+       if (gfan_handle) {
+               /* 570, 600e/x, 770e, 770x */
+               fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
+       } else {
+               /* all other ThinkPads: note that even old-style
+                * ThinkPad ECs supports the fan control register */
+               if (likely(acpi_ec_read(fan_status_offset,
+                                       &fan_control_initial_status))) {
+                       fan_status_access_mode = TPACPI_FAN_RD_TPEC;
+
+                       /* In some ThinkPads, neither the EC nor the ACPI
+                        * DSDT initialize the fan status, and it ends up
+                        * being set to 0x07 when it *could* be either
+                        * 0x07 or 0x80.
+                        *
+                        * Enable for TP-1Y (T43), TP-78 (R51e),
+                        * TP-76 (R52), TP-70 (T43, R52), which are known
+                        * to be buggy. */
+                       if (fan_control_initial_status == 0x07) {
+                               switch (thinkpad_id.ec_model) {
+                               case 0x5931: /* TP-1Y */
+                               case 0x3837: /* TP-78 */
+                               case 0x3637: /* TP-76 */
+                               case 0x3037: /* TP-70 */
+                                       printk(TPACPI_NOTICE
+                                              "fan_init: initial fan status "
+                                              "is unknown, assuming it is "
+                                              "in auto mode\n");
+                                       tp_features.fan_ctrl_status_undef = 1;
+                                       ;;
+                               }
+                       }
+               } else {
+                       printk(TPACPI_ERR
+                              "ThinkPad ACPI EC access misbehaving, "
+                              "fan status and control unavailable\n");
+                       return 1;
                }
-               break;
+       }
 
-       case TPACPI_FAN_WR_ACPI_SFAN:
-               if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
-                       rc = -EIO;
-               else
-                       fan_control_desired_level = 0;
-               break;
+       if (sfan_handle) {
+               /* 570, 770x-JL */
+               fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN;
+               fan_control_commands |=
+                   TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE;
+       } else {
+               if (!gfan_handle) {
+                       /* gfan without sfan means no fan control */
+                       /* all other models implement TP EC 0x2f control */
 
-       default:
-               rc = -ENXIO;
+                       if (fans_handle) {
+                               /* X31, X40, X41 */
+                               fan_control_access_mode =
+                                   TPACPI_FAN_WR_ACPI_FANS;
+                               fan_control_commands |=
+                                   TPACPI_FAN_CMD_SPEED |
+                                   TPACPI_FAN_CMD_LEVEL |
+                                   TPACPI_FAN_CMD_ENABLE;
+                       } else {
+                               fan_control_access_mode = TPACPI_FAN_WR_TPEC;
+                               fan_control_commands |=
+                                   TPACPI_FAN_CMD_LEVEL |
+                                   TPACPI_FAN_CMD_ENABLE;
+                       }
+               }
+       }
+
+       vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n",
+               str_supported(fan_status_access_mode != TPACPI_FAN_NONE ||
+                 fan_control_access_mode != TPACPI_FAN_WR_NONE),
+               fan_status_access_mode, fan_control_access_mode);
+
+       /* fan control master switch */
+       if (!fan_control_allowed) {
+               fan_control_access_mode = TPACPI_FAN_WR_NONE;
+               fan_control_commands = 0;
+               dbg_printk(TPACPI_DBG_INIT,
+                          "fan control features disabled by parameter\n");
        }
 
+       /* update fan_control_desired_level */
+       if (fan_status_access_mode != TPACPI_FAN_NONE)
+               fan_get_status_safe(NULL);
 
-       mutex_unlock(&fan_mutex);
-       return rc;
+       if (fan_status_access_mode != TPACPI_FAN_NONE ||
+           fan_control_access_mode != TPACPI_FAN_WR_NONE) {
+               rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
+                                        &fan_attr_group);
+               if (!(rc < 0))
+                       rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
+                                       &driver_attr_fan_watchdog);
+               if (rc < 0)
+                       return rc;
+               return 0;
+       } else
+               return 1;
 }
 
-static int fan_set_speed(int speed)
+static void fan_exit(void)
 {
-       int rc;
-
-       if (!fan_control_allowed)
-               return -EPERM;
-
-       if (mutex_lock_interruptible(&fan_mutex))
-               return -ERESTARTSYS;
-
-       rc = 0;
-       switch (fan_control_access_mode) {
-       case TPACPI_FAN_WR_ACPI_FANS:
-               if (speed >= 0 && speed <= 65535) {
-                       if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
-                                       speed, speed, speed))
-                               rc = -EIO;
-               } else
-                       rc = -EINVAL;
-               break;
+       vdbg_printk(TPACPI_DBG_EXIT,
+                   "cancelling any pending fan watchdog tasks\n");
 
-       default:
-               rc = -ENXIO;
-       }
+       /* FIXME: can we really do this unconditionally? */
+       sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
+       driver_remove_file(&tpacpi_hwmon_pdriver.driver,
+                          &driver_attr_fan_watchdog);
 
-       mutex_unlock(&fan_mutex);
-       return rc;
+       cancel_delayed_work(&fan_watchdog_task);
+       flush_scheduled_work();
 }
 
 static int fan_read(char *p)
@@ -4307,7 +5349,8 @@ static int fan_read(char *p)
        switch (fan_status_access_mode) {
        case TPACPI_FAN_RD_ACPI_GFAN:
                /* 570, 600e/x, 770e, 770x */
-               if ((rc = fan_get_status_safe(&status)) < 0)
+               rc = fan_get_status_safe(&status);
+               if (rc < 0)
                        return rc;
 
                len += sprintf(p + len, "status:\t\t%s\n"
@@ -4317,7 +5360,8 @@ static int fan_read(char *p)
 
        case TPACPI_FAN_RD_TPEC:
                /* all except 570, 600e/x, 770e, 770x */
-               if ((rc = fan_get_status_safe(&status)) < 0)
+               rc = fan_get_status_safe(&status);
+               if (rc < 0)
                        return rc;
 
                if (unlikely(tp_features.fan_ctrl_status_undef)) {
@@ -4332,7 +5376,8 @@ static int fan_read(char *p)
                len += sprintf(p + len, "status:\t\t%s\n",
                               (status != 0) ? "enabled" : "disabled");
 
-               if ((rc = fan_get_speed(&speed)) < 0)
+               rc = fan_get_speed(&speed);
+               if (rc < 0)
                        return rc;
 
                len += sprintf(p + len, "speed:\t\t%d\n", speed);
@@ -4368,8 +5413,8 @@ static int fan_read(char *p)
 
        if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
                len += sprintf(p + len, "commands:\tenable, disable\n"
-                              "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
-                              "1-120 (seconds))\n");
+                              "commands:\twatchdog <timeout> (<timeout> "
+                              "is 0 (off), 1-120 (seconds))\n");
 
        if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
                len += sprintf(p + len, "commands:\tspeed <speed>"
@@ -4385,13 +5430,14 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
        if (strlencmp(cmd, "level auto") == 0)
                level = TP_EC_FAN_AUTO;
        else if ((strlencmp(cmd, "level disengaged") == 0) |
-                (strlencmp(cmd, "level full-speed") == 0))
+                       (strlencmp(cmd, "level full-speed") == 0))
                level = TP_EC_FAN_FULLSPEED;
        else if (sscanf(cmd, "level %d", &level) != 1)
                return 0;
 
-       if ((*rc = fan_set_level_safe(level)) == -ENXIO)
-               printk(IBM_ERR "level command accepted for unsupported "
+       *rc = fan_set_level_safe(level);
+       if (*rc == -ENXIO)
+               printk(TPACPI_ERR "level command accepted for unsupported "
                       "access mode %d", fan_control_access_mode);
 
        return 1;
@@ -4402,8 +5448,9 @@ static int fan_write_cmd_enable(const char *cmd, int *rc)
        if (strlencmp(cmd, "enable") != 0)
                return 0;
 
-       if ((*rc = fan_set_enable()) == -ENXIO)
-               printk(IBM_ERR "enable command accepted for unsupported "
+       *rc = fan_set_enable();
+       if (*rc == -ENXIO)
+               printk(TPACPI_ERR "enable command accepted for unsupported "
                       "access mode %d", fan_control_access_mode);
 
        return 1;
@@ -4414,8 +5461,9 @@ static int fan_write_cmd_disable(const char *cmd, int *rc)
        if (strlencmp(cmd, "disable") != 0)
                return 0;
 
-       if ((*rc = fan_set_disable()) == -ENXIO)
-               printk(IBM_ERR "disable command accepted for unsupported "
+       *rc = fan_set_disable();
+       if (*rc == -ENXIO)
+               printk(TPACPI_ERR "disable command accepted for unsupported "
                       "access mode %d", fan_control_access_mode);
 
        return 1;
@@ -4431,8 +5479,9 @@ static int fan_write_cmd_speed(const char *cmd, int *rc)
        if (sscanf(cmd, "speed %d", &speed) != 1)
                return 0;
 
-       if ((*rc = fan_set_speed(speed)) == -ENXIO)
-               printk(IBM_ERR "speed command accepted for unsupported "
+       *rc = fan_set_speed(speed);
+       if (*rc == -ENXIO)
+               printk(TPACPI_ERR "speed command accepted for unsupported "
                       "access mode %d", fan_control_access_mode);
 
        return 1;
@@ -4496,7 +5545,7 @@ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME);
+       return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME);
 }
 
 static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
@@ -4507,14 +5556,12 @@ static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
 /* /proc support */
 static struct proc_dir_entry *proc_dir;
 
-/* Subdriver registry */
-static LIST_HEAD(tpacpi_all_drivers);
-
-
 /*
  * Module and infrastructure proble, init and exit handling
  */
 
+static int force_load;
+
 #ifdef CONFIG_THINKPAD_ACPI_DEBUG
 static const char * __init str_supported(int is_supported)
 {
@@ -4524,6 +5571,48 @@ static const char * __init str_supported(int is_supported)
 }
 #endif /* CONFIG_THINKPAD_ACPI_DEBUG */
 
+static void ibm_exit(struct ibm_struct *ibm)
+{
+       dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
+
+       list_del_init(&ibm->all_drivers);
+
+       if (ibm->flags.acpi_notify_installed) {
+               dbg_printk(TPACPI_DBG_EXIT,
+                       "%s: acpi_remove_notify_handler\n", ibm->name);
+               BUG_ON(!ibm->acpi);
+               acpi_remove_notify_handler(*ibm->acpi->handle,
+                                          ibm->acpi->type,
+                                          dispatch_acpi_notify);
+               ibm->flags.acpi_notify_installed = 0;
+               ibm->flags.acpi_notify_installed = 0;
+       }
+
+       if (ibm->flags.proc_created) {
+               dbg_printk(TPACPI_DBG_EXIT,
+                       "%s: remove_proc_entry\n", ibm->name);
+               remove_proc_entry(ibm->name, proc_dir);
+               ibm->flags.proc_created = 0;
+       }
+
+       if (ibm->flags.acpi_driver_registered) {
+               dbg_printk(TPACPI_DBG_EXIT,
+                       "%s: acpi_bus_unregister_driver\n", ibm->name);
+               BUG_ON(!ibm->acpi);
+               acpi_bus_unregister_driver(ibm->acpi->driver);
+               kfree(ibm->acpi->driver);
+               ibm->acpi->driver = NULL;
+               ibm->flags.acpi_driver_registered = 0;
+       }
+
+       if (ibm->flags.init_called && ibm->exit) {
+               ibm->exit();
+               ibm->flags.init_called = 0;
+       }
+
+       dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
+}
+
 static int __init ibm_init(struct ibm_init_struct *iibm)
 {
        int ret;
@@ -4560,7 +5649,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
                if (ibm->acpi->notify) {
                        ret = setup_acpi_notify(ibm);
                        if (ret == -ENODEV) {
-                               printk(IBM_NOTICE "disabling subdriver %s\n",
+                               printk(TPACPI_NOTICE "disabling subdriver %s\n",
                                        ibm->name);
                                ret = 0;
                                goto err_out;
@@ -4578,7 +5667,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
                                          S_IFREG | S_IRUGO | S_IWUSR,
                                          proc_dir);
                if (!entry) {
-                       printk(IBM_ERR "unable to create proc entry %s\n",
+                       printk(TPACPI_ERR "unable to create proc entry %s\n",
                               ibm->name);
                        ret = -ENODEV;
                        goto err_out;
@@ -4604,48 +5693,6 @@ err_out:
        return (ret < 0)? ret : 0;
 }
 
-static void ibm_exit(struct ibm_struct *ibm)
-{
-       dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
-
-       list_del_init(&ibm->all_drivers);
-
-       if (ibm->flags.acpi_notify_installed) {
-               dbg_printk(TPACPI_DBG_EXIT,
-                       "%s: acpi_remove_notify_handler\n", ibm->name);
-               BUG_ON(!ibm->acpi);
-               acpi_remove_notify_handler(*ibm->acpi->handle,
-                                          ibm->acpi->type,
-                                          dispatch_acpi_notify);
-               ibm->flags.acpi_notify_installed = 0;
-               ibm->flags.acpi_notify_installed = 0;
-       }
-
-       if (ibm->flags.proc_created) {
-               dbg_printk(TPACPI_DBG_EXIT,
-                       "%s: remove_proc_entry\n", ibm->name);
-               remove_proc_entry(ibm->name, proc_dir);
-               ibm->flags.proc_created = 0;
-       }
-
-       if (ibm->flags.acpi_driver_registered) {
-               dbg_printk(TPACPI_DBG_EXIT,
-                       "%s: acpi_bus_unregister_driver\n", ibm->name);
-               BUG_ON(!ibm->acpi);
-               acpi_bus_unregister_driver(ibm->acpi->driver);
-               kfree(ibm->acpi->driver);
-               ibm->acpi->driver = NULL;
-               ibm->flags.acpi_driver_registered = 0;
-       }
-
-       if (ibm->flags.init_called && ibm->exit) {
-               ibm->exit();
-               ibm->flags.init_called = 0;
-       }
-
-       dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
-}
-
 /* Probing */
 
 static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
@@ -4715,10 +5762,10 @@ static int __init probe_for_thinkpad(void)
        is_thinkpad = (thinkpad_id.model_str != NULL);
 
        /* ec is required because many other handles are relative to it */
-       IBM_ACPIHANDLE_INIT(ec);
+       TPACPI_ACPIHANDLE_INIT(ec);
        if (!ec_handle) {
                if (is_thinkpad)
-                       printk(IBM_ERR
+                       printk(TPACPI_ERR
                                "Not yet supported ThinkPad detected!\n");
                return -ENODEV;
        }
@@ -4839,47 +5886,110 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp)
        return -EINVAL;
 }
 
-static int experimental;
 module_param(experimental, int, 0);
+MODULE_PARM_DESC(experimental,
+                "Enables experimental features when non-zero");
 
-static u32 dbg_level;
 module_param_named(debug, dbg_level, uint, 0);
+MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
 
-static int force_load;
 module_param(force_load, bool, 0);
+MODULE_PARM_DESC(force_load,
+                "Attempts to load the driver even on a "
+                "mis-identified ThinkPad when true");
 
-static int fan_control_allowed;
 module_param_named(fan_control, fan_control_allowed, bool, 0);
+MODULE_PARM_DESC(fan_control,
+                "Enables setting fan parameters features when true");
 
-static int brightness_mode;
 module_param_named(brightness_mode, brightness_mode, int, 0);
+MODULE_PARM_DESC(brightness_mode,
+                "Selects brightness control strategy: "
+                "0=auto, 1=EC, 2=CMOS, 3=both");
 
-static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
 module_param(brightness_enable, uint, 0);
+MODULE_PARM_DESC(brightness_enable,
+                "Enables backlight control when 1, disables when 0");
 
-static unsigned int hotkey_report_mode;
 module_param(hotkey_report_mode, uint, 0);
-
-#define IBM_PARAM(feature) \
-       module_param_call(feature, set_ibm_param, NULL, NULL, 0)
-
-IBM_PARAM(hotkey);
-IBM_PARAM(bluetooth);
-IBM_PARAM(video);
-IBM_PARAM(light);
+MODULE_PARM_DESC(hotkey_report_mode,
+                "used for backwards compatibility with userspace, "
+                "see documentation");
+
+#define TPACPI_PARAM(feature) \
+       module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
+       MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \
+                        "at module load, see documentation")
+
+TPACPI_PARAM(hotkey);
+TPACPI_PARAM(bluetooth);
+TPACPI_PARAM(video);
+TPACPI_PARAM(light);
 #ifdef CONFIG_THINKPAD_ACPI_DOCK
-IBM_PARAM(dock);
+TPACPI_PARAM(dock);
 #endif
 #ifdef CONFIG_THINKPAD_ACPI_BAY
-IBM_PARAM(bay);
+TPACPI_PARAM(bay);
 #endif /* CONFIG_THINKPAD_ACPI_BAY */
-IBM_PARAM(cmos);
-IBM_PARAM(led);
-IBM_PARAM(beep);
-IBM_PARAM(ecdump);
-IBM_PARAM(brightness);
-IBM_PARAM(volume);
-IBM_PARAM(fan);
+TPACPI_PARAM(cmos);
+TPACPI_PARAM(led);
+TPACPI_PARAM(beep);
+TPACPI_PARAM(ecdump);
+TPACPI_PARAM(brightness);
+TPACPI_PARAM(volume);
+TPACPI_PARAM(fan);
+
+static void thinkpad_acpi_module_exit(void)
+{
+       struct ibm_struct *ibm, *itmp;
+
+       tpacpi_lifecycle = TPACPI_LIFE_EXITING;
+
+       list_for_each_entry_safe_reverse(ibm, itmp,
+                                        &tpacpi_all_drivers,
+                                        all_drivers) {
+               ibm_exit(ibm);
+       }
+
+       dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
+
+       if (tpacpi_inputdev) {
+               if (tp_features.input_device_registered)
+                       input_unregister_device(tpacpi_inputdev);
+               else
+                       input_free_device(tpacpi_inputdev);
+       }
+
+       if (tpacpi_hwmon)
+               hwmon_device_unregister(tpacpi_hwmon);
+
+       if (tp_features.sensors_pdev_attrs_registered)
+               device_remove_file(&tpacpi_sensors_pdev->dev,
+                                  &dev_attr_thinkpad_acpi_pdev_name);
+       if (tpacpi_sensors_pdev)
+               platform_device_unregister(tpacpi_sensors_pdev);
+       if (tpacpi_pdev)
+               platform_device_unregister(tpacpi_pdev);
+
+       if (tp_features.sensors_pdrv_attrs_registered)
+               tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
+       if (tp_features.platform_drv_attrs_registered)
+               tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+
+       if (tp_features.sensors_pdrv_registered)
+               platform_driver_unregister(&tpacpi_hwmon_pdriver);
+
+       if (tp_features.platform_drv_registered)
+               platform_driver_unregister(&tpacpi_pdriver);
+
+       if (proc_dir)
+               remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
+
+       kfree(thinkpad_id.bios_version_str);
+       kfree(thinkpad_id.ec_version_str);
+       kfree(thinkpad_id.model_str);
+}
+
 
 static int __init thinkpad_acpi_module_init(void)
 {
@@ -4902,12 +6012,13 @@ static int __init thinkpad_acpi_module_init(void)
 
        /* Driver initialization */
 
-       IBM_ACPIHANDLE_INIT(ecrd);
-       IBM_ACPIHANDLE_INIT(ecwr);
+       TPACPI_ACPIHANDLE_INIT(ecrd);
+       TPACPI_ACPIHANDLE_INIT(ecwr);
 
-       proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir);
+       proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir);
        if (!proc_dir) {
-               printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR);
+               printk(TPACPI_ERR
+                      "unable to create proc dir " TPACPI_PROC_DIR);
                thinkpad_acpi_module_exit();
                return -ENODEV;
        }
@@ -4915,7 +6026,8 @@ static int __init thinkpad_acpi_module_init(void)
 
        ret = platform_driver_register(&tpacpi_pdriver);
        if (ret) {
-               printk(IBM_ERR "unable to register main platform driver\n");
+               printk(TPACPI_ERR
+                      "unable to register main platform driver\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -4923,7 +6035,8 @@ static int __init thinkpad_acpi_module_init(void)
 
        ret = platform_driver_register(&tpacpi_hwmon_pdriver);
        if (ret) {
-               printk(IBM_ERR "unable to register hwmon platform driver\n");
+               printk(TPACPI_ERR
+                      "unable to register hwmon platform driver\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -4932,10 +6045,12 @@ static int __init thinkpad_acpi_module_init(void)
        ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
        if (!ret) {
                tp_features.platform_drv_attrs_registered = 1;
-               ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver);
+               ret = tpacpi_create_driver_attributes(
+                                       &tpacpi_hwmon_pdriver.driver);
        }
        if (ret) {
-               printk(IBM_ERR "unable to create sysfs driver attributes\n");
+               printk(TPACPI_ERR
+                      "unable to create sysfs driver attributes\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -4943,30 +6058,31 @@ static int __init thinkpad_acpi_module_init(void)
 
 
        /* Device initialization */
-       tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1,
+       tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1,
                                                        NULL, 0);
        if (IS_ERR(tpacpi_pdev)) {
                ret = PTR_ERR(tpacpi_pdev);
                tpacpi_pdev = NULL;
-               printk(IBM_ERR "unable to register platform device\n");
+               printk(TPACPI_ERR "unable to register platform device\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
        tpacpi_sensors_pdev = platform_device_register_simple(
-                                                       IBM_HWMON_DRVR_NAME,
-                                                       -1, NULL, 0);
+                                               TPACPI_HWMON_DRVR_NAME,
+                                               -1, NULL, 0);
        if (IS_ERR(tpacpi_sensors_pdev)) {
                ret = PTR_ERR(tpacpi_sensors_pdev);
                tpacpi_sensors_pdev = NULL;
-               printk(IBM_ERR "unable to register hwmon platform device\n");
+               printk(TPACPI_ERR
+                      "unable to register hwmon platform device\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
        ret = device_create_file(&tpacpi_sensors_pdev->dev,
                                 &dev_attr_thinkpad_acpi_pdev_name);
        if (ret) {
-               printk(IBM_ERR
-                       "unable to create sysfs hwmon device attributes\n");
+               printk(TPACPI_ERR
+                      "unable to create sysfs hwmon device attributes\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -4975,20 +6091,20 @@ static int __init thinkpad_acpi_module_init(void)
        if (IS_ERR(tpacpi_hwmon)) {
                ret = PTR_ERR(tpacpi_hwmon);
                tpacpi_hwmon = NULL;
-               printk(IBM_ERR "unable to register hwmon device\n");
+               printk(TPACPI_ERR "unable to register hwmon device\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
        mutex_init(&tpacpi_inputdev_send_mutex);
        tpacpi_inputdev = input_allocate_device();
        if (!tpacpi_inputdev) {
-               printk(IBM_ERR "unable to allocate input device\n");
+               printk(TPACPI_ERR "unable to allocate input device\n");
                thinkpad_acpi_module_exit();
                return -ENOMEM;
        } else {
                /* Prepare input device, but don't register */
                tpacpi_inputdev->name = "ThinkPad Extra Buttons";
-               tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
+               tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0";
                tpacpi_inputdev->id.bustype = BUS_HOST;
                tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
                                                thinkpad_id.vendor :
@@ -5007,7 +6123,7 @@ static int __init thinkpad_acpi_module_init(void)
        }
        ret = input_register_device(tpacpi_inputdev);
        if (ret < 0) {
-               printk(IBM_ERR "unable to register input device\n");
+               printk(TPACPI_ERR "unable to register input device\n");
                thinkpad_acpi_module_exit();
                return ret;
        } else {
@@ -5018,56 +6134,36 @@ static int __init thinkpad_acpi_module_init(void)
        return 0;
 }
 
-static void thinkpad_acpi_module_exit(void)
-{
-       struct ibm_struct *ibm, *itmp;
-
-       tpacpi_lifecycle = TPACPI_LIFE_EXITING;
-
-       list_for_each_entry_safe_reverse(ibm, itmp,
-                                        &tpacpi_all_drivers,
-                                        all_drivers) {
-               ibm_exit(ibm);
-       }
-
-       dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
-
-       if (tpacpi_inputdev) {
-               if (tp_features.input_device_registered)
-                       input_unregister_device(tpacpi_inputdev);
-               else
-                       input_free_device(tpacpi_inputdev);
-       }
-
-       if (tpacpi_hwmon)
-               hwmon_device_unregister(tpacpi_hwmon);
-
-       if (tp_features.sensors_pdev_attrs_registered)
-               device_remove_file(&tpacpi_sensors_pdev->dev,
-                                  &dev_attr_thinkpad_acpi_pdev_name);
-       if (tpacpi_sensors_pdev)
-               platform_device_unregister(tpacpi_sensors_pdev);
-       if (tpacpi_pdev)
-               platform_device_unregister(tpacpi_pdev);
-
-       if (tp_features.sensors_pdrv_attrs_registered)
-               tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
-       if (tp_features.platform_drv_attrs_registered)
-               tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+/* Please remove this in year 2009 */
+MODULE_ALIAS("ibm_acpi");
 
-       if (tp_features.sensors_pdrv_registered)
-               platform_driver_unregister(&tpacpi_hwmon_pdriver);
+/*
+ * DMI matching for module autoloading
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
+ *
+ * Only models listed in thinkwiki will be supported, so add yours
+ * if it is not there yet.
+ */
+#define IBM_BIOS_MODULE_ALIAS(__type) \
+       MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
 
-       if (tp_features.platform_drv_registered)
-               platform_driver_unregister(&tpacpi_pdriver);
+/* Non-ancient thinkpads */
+MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
+MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
 
-       if (proc_dir)
-               remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
+/* Ancient thinkpad BIOSes have to be identified by
+ * BIOS type or model number, and there are far less
+ * BIOS types than model numbers... */
+IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
+IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
+IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
 
-       kfree(thinkpad_id.bios_version_str);
-       kfree(thinkpad_id.ec_version_str);
-       kfree(thinkpad_id.model_str);
-}
+MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
+MODULE_DESCRIPTION(TPACPI_DESC);
+MODULE_VERSION(TPACPI_VERSION);
+MODULE_LICENSE("GPL");
 
 module_init(thinkpad_acpi_module_init);
 module_exit(thinkpad_acpi_module_exit);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
deleted file mode 100644 (file)
index 8fba2bb..0000000
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- *  thinkpad_acpi.h - ThinkPad ACPI Extras
- *
- *
- *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
- *  Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
- *
- *  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., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
- */
-
-#ifndef __THINKPAD_ACPI_H__
-#define __THINKPAD_ACPI_H__
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-
-#include <linux/nvram.h>
-#include <linux/proc_fs.h>
-#include <linux/sysfs.h>
-#include <linux/backlight.h>
-#include <linux/fb.h>
-#include <linux/platform_device.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/input.h>
-#include <asm/uaccess.h>
-
-#include <linux/dmi.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-
-#include <acpi/acpi_drivers.h>
-#include <acpi/acnamesp.h>
-
-#include <linux/pci_ids.h>
-
-/****************************************************************************
- * Main driver
- */
-
-#define IBM_NAME "thinkpad"
-#define IBM_DESC "ThinkPad ACPI Extras"
-#define IBM_FILE IBM_NAME "_acpi"
-#define IBM_URL "http://ibm-acpi.sf.net/"
-#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
-
-#define IBM_PROC_DIR "ibm"
-#define IBM_ACPI_EVENT_PREFIX "ibm"
-#define IBM_DRVR_NAME IBM_FILE
-#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon"
-
-#define IBM_LOG IBM_FILE ": "
-#define IBM_ERR           KERN_ERR    IBM_LOG
-#define IBM_NOTICE KERN_NOTICE IBM_LOG
-#define IBM_INFO   KERN_INFO   IBM_LOG
-#define IBM_DEBUG  KERN_DEBUG  IBM_LOG
-
-#define IBM_MAX_ACPI_ARGS 3
-
-/* ThinkPad CMOS commands */
-#define TP_CMOS_VOLUME_DOWN    0
-#define TP_CMOS_VOLUME_UP      1
-#define TP_CMOS_VOLUME_MUTE    2
-#define TP_CMOS_BRIGHTNESS_UP  4
-#define TP_CMOS_BRIGHTNESS_DOWN        5
-
-/* ThinkPad CMOS NVRAM constants */
-#define TP_NVRAM_ADDR_BRIGHTNESS       0x5e
-#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f
-#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
-
-#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
-#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
-#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
-
-/* Debugging */
-#define TPACPI_DBG_ALL         0xffff
-#define TPACPI_DBG_ALL         0xffff
-#define TPACPI_DBG_INIT                0x0001
-#define TPACPI_DBG_EXIT                0x0002
-#define dbg_printk(a_dbg_level, format, arg...) \
-       do { if (dbg_level & a_dbg_level) \
-               printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
-#ifdef CONFIG_THINKPAD_ACPI_DEBUG
-#define vdbg_printk(a_dbg_level, format, arg...) \
-       dbg_printk(a_dbg_level, format, ## arg)
-static const char *str_supported(int is_supported);
-#else
-#define vdbg_printk(a_dbg_level, format, arg...)
-#endif
-
-/* Input IDs */
-#define TPACPI_HKEY_INPUT_VENDOR       PCI_VENDOR_ID_IBM
-#define TPACPI_HKEY_INPUT_PRODUCT      0x5054 /* "TP" */
-#define TPACPI_HKEY_INPUT_VERSION      0x4101
-
-/* ACPI HIDs */
-#define IBM_HKEY_HID    "IBM0068"
-
-/* ACPI helpers */
-static int __must_check acpi_evalf(acpi_handle handle,
-                     void *res, char *method, char *fmt, ...);
-static int __must_check acpi_ec_read(int i, u8 * p);
-static int __must_check acpi_ec_write(int i, u8 v);
-static int __must_check _sta(acpi_handle handle);
-
-/* ACPI handles */
-static acpi_handle root_handle;                        /* root namespace */
-static acpi_handle ec_handle;                  /* EC */
-static acpi_handle ecrd_handle, ecwr_handle;   /* 570 EC access */
-static acpi_handle cmos_handle, hkey_handle;   /* basic thinkpad handles */
-
-static void drv_acpi_handle_init(char *name,
-                  acpi_handle *handle, acpi_handle parent,
-                  char **paths, int num_paths, char **path);
-#define IBM_ACPIHANDLE_INIT(object)                                            \
-       drv_acpi_handle_init(#object, &object##_handle, *object##_parent,       \
-               object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
-
-/* ThinkPad ACPI helpers */
-static int issue_thinkpad_cmos_command(int cmos_cmd);
-
-/* procfs support */
-static struct proc_dir_entry *proc_dir;
-
-/* procfs helpers */
-static int dispatch_procfs_read(char *page, char **start, off_t off,
-               int count, int *eof, void *data);
-static int dispatch_procfs_write(struct file *file,
-               const char __user * userbuf,
-               unsigned long count, void *data);
-static char *next_cmd(char **cmds);
-
-/* sysfs support */
-struct attribute_set {
-       unsigned int members, max_members;
-       struct attribute_group group;
-};
-
-static struct attribute_set *create_attr_set(unsigned int max_members,
-                                               const char* name);
-#define destroy_attr_set(_set) \
-       kfree(_set);
-static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
-static int add_many_to_attr_set(struct attribute_set* s,
-                       struct attribute **attr,
-                       unsigned int count);
-#define register_attr_set_with_sysfs(_attr_set, _kobj) \
-       sysfs_create_group(_kobj, &_attr_set->group)
-static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
-
-static int parse_strtoul(const char *buf, unsigned long max,
-                       unsigned long *value);
-
-/* Device model */
-static struct platform_device *tpacpi_pdev;
-static struct platform_device *tpacpi_sensors_pdev;
-static struct device *tpacpi_hwmon;
-static struct platform_driver tpacpi_pdriver;
-static struct input_dev *tpacpi_inputdev;
-static int tpacpi_create_driver_attributes(struct device_driver *drv);
-static void tpacpi_remove_driver_attributes(struct device_driver *drv);
-
-/* Module */
-static int experimental;
-static u32 dbg_level;
-static int force_load;
-static unsigned int hotkey_report_mode;
-
-static int thinkpad_acpi_module_init(void);
-static void thinkpad_acpi_module_exit(void);
-
-
-/****************************************************************************
- * Subdrivers
- */
-
-struct ibm_struct;
-
-struct tp_acpi_drv_struct {
-       const struct acpi_device_id *hid;
-       struct acpi_driver *driver;
-
-       void (*notify) (struct ibm_struct *, u32);
-       acpi_handle *handle;
-       u32 type;
-       struct acpi_device *device;
-};
-
-struct ibm_struct {
-       char *name;
-
-       int (*read) (char *);
-       int (*write) (char *);
-       void (*exit) (void);
-       void (*resume) (void);
-
-       struct list_head all_drivers;
-
-       struct tp_acpi_drv_struct *acpi;
-
-       struct {
-               u8 acpi_driver_registered:1;
-               u8 acpi_notify_installed:1;
-               u8 proc_created:1;
-               u8 init_called:1;
-               u8 experimental:1;
-       } flags;
-};
-
-struct ibm_init_struct {
-       char param[32];
-
-       int (*init) (struct ibm_init_struct *);
-       struct ibm_struct *data;
-};
-
-static struct {
-#ifdef CONFIG_THINKPAD_ACPI_BAY
-       u32 bay_status:1;
-       u32 bay_eject:1;
-       u32 bay_status2:1;
-       u32 bay_eject2:1;
-#endif
-       u32 bluetooth:1;
-       u32 hotkey:1;
-       u32 hotkey_mask:1;
-       u32 hotkey_wlsw:1;
-       u32 light:1;
-       u32 light_status:1;
-       u32 bright_16levels:1;
-       u32 wan:1;
-       u32 fan_ctrl_status_undef:1;
-       u32 input_device_registered:1;
-       u32 platform_drv_registered:1;
-       u32 platform_drv_attrs_registered:1;
-       u32 sensors_pdrv_registered:1;
-       u32 sensors_pdrv_attrs_registered:1;
-       u32 sensors_pdev_attrs_registered:1;
-} tp_features;
-
-struct thinkpad_id_data {
-       unsigned int vendor;    /* ThinkPad vendor:
-                                * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
-
-       char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
-       char *ec_version_str;   /* Something like 1ZHT51WW-1.04a */
-
-       u16 bios_model;         /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
-       u16 ec_model;
-
-       char *model_str;
-};
-
-static struct thinkpad_id_data thinkpad_id;
-
-static struct list_head tpacpi_all_drivers;
-
-static struct ibm_init_struct ibms_init[];
-static int set_ibm_param(const char *val, struct kernel_param *kp);
-static int ibm_init(struct ibm_init_struct *iibm);
-static void ibm_exit(struct ibm_struct *ibm);
-
-
-/*
- * procfs master subdriver
- */
-static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
-static int thinkpad_acpi_driver_read(char *p);
-
-
-/*
- * Bay subdriver
- */
-
-#ifdef CONFIG_THINKPAD_ACPI_BAY
-static acpi_handle bay_handle, bay_ej_handle;
-static acpi_handle bay2_handle, bay2_ej_handle;
-
-static int bay_init(struct ibm_init_struct *iibm);
-static void bay_notify(struct ibm_struct *ibm, u32 event);
-static int bay_read(char *p);
-static int bay_write(char *buf);
-#endif /* CONFIG_THINKPAD_ACPI_BAY */
-
-
-/*
- * Beep subdriver
- */
-
-static acpi_handle beep_handle;
-
-static int beep_read(char *p);
-static int beep_write(char *buf);
-
-
-/*
- * Bluetooth subdriver
- */
-
-enum {
-       /* ACPI GBDC/SBDC bits */
-       TP_ACPI_BLUETOOTH_HWPRESENT     = 0x01, /* Bluetooth hw available */
-       TP_ACPI_BLUETOOTH_RADIOSSW      = 0x02, /* Bluetooth radio enabled */
-       TP_ACPI_BLUETOOTH_UNK           = 0x04, /* unknown function */
-};
-
-static int bluetooth_init(struct ibm_init_struct *iibm);
-static int bluetooth_get_radiosw(void);
-static int bluetooth_set_radiosw(int radio_on);
-static int bluetooth_read(char *p);
-static int bluetooth_write(char *buf);
-
-
-/*
- * Brightness (backlight) subdriver
- */
-
-#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
-
-static struct backlight_device *ibm_backlight_device;
-static int brightness_offset = 0x31;
-static int brightness_mode;
-static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */
-
-static int brightness_init(struct ibm_init_struct *iibm);
-static void brightness_exit(void);
-static int brightness_get(struct backlight_device *bd);
-static int brightness_set(int value);
-static int brightness_update_status(struct backlight_device *bd);
-static int brightness_read(char *p);
-static int brightness_write(char *buf);
-
-
-/*
- * CMOS subdriver
- */
-
-static int cmos_read(char *p);
-static int cmos_write(char *buf);
-
-
-/*
- * Dock subdriver
- */
-
-#ifdef CONFIG_THINKPAD_ACPI_DOCK
-static acpi_handle pci_handle;
-static acpi_handle dock_handle;
-
-static void dock_notify(struct ibm_struct *ibm, u32 event);
-static int dock_read(char *p);
-static int dock_write(char *buf);
-#endif /* CONFIG_THINKPAD_ACPI_DOCK */
-
-
-/*
- * EC dump subdriver
- */
-
-static int ecdump_read(char *p) ;
-static int ecdump_write(char *buf);
-
-
-/*
- * Fan subdriver
- */
-
-enum {                                 /* Fan control constants */
-       fan_status_offset = 0x2f,       /* EC register 0x2f */
-       fan_rpm_offset = 0x84,          /* EC register 0x84: LSB, 0x85 MSB (RPM)
-                                        * 0x84 must be read before 0x85 */
-
-       TP_EC_FAN_FULLSPEED = 0x40,     /* EC fan mode: full speed */
-       TP_EC_FAN_AUTO      = 0x80,     /* EC fan mode: auto fan control */
-
-       TPACPI_FAN_LAST_LEVEL = 0x100,  /* Use cached last-seen fan level */
-};
-
-enum fan_status_access_mode {
-       TPACPI_FAN_NONE = 0,            /* No fan status or control */
-       TPACPI_FAN_RD_ACPI_GFAN,        /* Use ACPI GFAN */
-       TPACPI_FAN_RD_TPEC,             /* Use ACPI EC regs 0x2f, 0x84-0x85 */
-};
-
-enum fan_control_access_mode {
-       TPACPI_FAN_WR_NONE = 0,         /* No fan control */
-       TPACPI_FAN_WR_ACPI_SFAN,        /* Use ACPI SFAN */
-       TPACPI_FAN_WR_TPEC,             /* Use ACPI EC reg 0x2f */
-       TPACPI_FAN_WR_ACPI_FANS,        /* Use ACPI FANS and EC reg 0x2f */
-};
-
-enum fan_control_commands {
-       TPACPI_FAN_CMD_SPEED    = 0x0001,       /* speed command */
-       TPACPI_FAN_CMD_LEVEL    = 0x0002,       /* level command  */
-       TPACPI_FAN_CMD_ENABLE   = 0x0004,       /* enable/disable cmd,
-                                                * and also watchdog cmd */
-};
-
-static int fan_control_allowed;
-
-static enum fan_status_access_mode fan_status_access_mode;
-static enum fan_control_access_mode fan_control_access_mode;
-static enum fan_control_commands fan_control_commands;
-static u8 fan_control_initial_status;
-static u8 fan_control_desired_level;
-static int fan_watchdog_maxinterval;
-
-static struct mutex fan_mutex;
-
-static acpi_handle fans_handle, gfan_handle, sfan_handle;
-
-static int fan_init(struct ibm_init_struct *iibm);
-static void fan_exit(void);
-static int fan_get_status(u8 *status);
-static int fan_get_status_safe(u8 *status);
-static int fan_get_speed(unsigned int *speed);
-static void fan_update_desired_level(u8 status);
-static void fan_watchdog_fire(struct work_struct *ignored);
-static void fan_watchdog_reset(void);
-static int fan_set_level(int level);
-static int fan_set_level_safe(int level);
-static int fan_set_enable(void);
-static int fan_set_disable(void);
-static int fan_set_speed(int speed);
-static int fan_read(char *p);
-static int fan_write(char *buf);
-static int fan_write_cmd_level(const char *cmd, int *rc);
-static int fan_write_cmd_enable(const char *cmd, int *rc);
-static int fan_write_cmd_disable(const char *cmd, int *rc);
-static int fan_write_cmd_speed(const char *cmd, int *rc);
-static int fan_write_cmd_watchdog(const char *cmd, int *rc);
-
-
-/*
- * Hotkey subdriver
- */
-
-static int hotkey_orig_status;
-static u32 hotkey_orig_mask;
-
-static struct mutex hotkey_mutex;
-
-static int hotkey_init(struct ibm_init_struct *iibm);
-static void hotkey_exit(void);
-static int hotkey_get(int *status, u32 *mask);
-static int hotkey_set(int status, u32 mask);
-static void hotkey_notify(struct ibm_struct *ibm, u32 event);
-static int hotkey_read(char *p);
-static int hotkey_write(char *buf);
-
-
-/*
- * LED subdriver
- */
-
-enum led_access_mode {
-       TPACPI_LED_NONE = 0,
-       TPACPI_LED_570, /* 570 */
-       TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
-       TPACPI_LED_NEW, /* all others */
-};
-
-enum { /* For TPACPI_LED_OLD */
-       TPACPI_LED_EC_HLCL = 0x0c,      /* EC reg to get led to power on */
-       TPACPI_LED_EC_HLBL = 0x0d,      /* EC reg to blink a lit led */
-       TPACPI_LED_EC_HLMS = 0x0e,      /* EC reg to select led to command */
-};
-
-static enum led_access_mode led_supported;
-static acpi_handle led_handle;
-
-static int led_init(struct ibm_init_struct *iibm);
-static int led_read(char *p);
-static int led_write(char *buf);
-
-/*
- * Light (thinklight) subdriver
- */
-
-static acpi_handle lght_handle, ledb_handle;
-
-static int light_init(struct ibm_init_struct *iibm);
-static int light_read(char *p);
-static int light_write(char *buf);
-
-
-/*
- * Thermal subdriver
- */
-
-enum thermal_access_mode {
-       TPACPI_THERMAL_NONE = 0,        /* No thermal support */
-       TPACPI_THERMAL_ACPI_TMP07,      /* Use ACPI TMP0-7 */
-       TPACPI_THERMAL_ACPI_UPDT,       /* Use ACPI TMP0-7 with UPDT */
-       TPACPI_THERMAL_TPEC_8,          /* Use ACPI EC regs, 8 sensors */
-       TPACPI_THERMAL_TPEC_16,         /* Use ACPI EC regs, 16 sensors */
-};
-
-enum { /* TPACPI_THERMAL_TPEC_* */
-       TP_EC_THERMAL_TMP0 = 0x78,      /* ACPI EC regs TMP 0..7 */
-       TP_EC_THERMAL_TMP8 = 0xC0,      /* ACPI EC regs TMP 8..15 */
-       TP_EC_THERMAL_TMP_NA = -128,    /* ACPI EC sensor not available */
-};
-
-#define TPACPI_MAX_THERMAL_SENSORS 16  /* Max thermal sensors supported */
-struct ibm_thermal_sensors_struct {
-       s32 temp[TPACPI_MAX_THERMAL_SENSORS];
-};
-
-static enum thermal_access_mode thermal_read_mode;
-
-static int thermal_init(struct ibm_init_struct *iibm);
-static int thermal_get_sensor(int idx, s32 *value);
-static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
-static int thermal_read(char *p);
-
-
-/*
- * Video subdriver
- */
-
-enum video_access_mode {
-       TPACPI_VIDEO_NONE = 0,
-       TPACPI_VIDEO_570,       /* 570 */
-       TPACPI_VIDEO_770,       /* 600e/x, 770e, 770x */
-       TPACPI_VIDEO_NEW,       /* all others */
-};
-
-enum { /* video status flags, based on VIDEO_570 */
-       TP_ACPI_VIDEO_S_LCD = 0x01,     /* LCD output enabled */
-       TP_ACPI_VIDEO_S_CRT = 0x02,     /* CRT output enabled */
-       TP_ACPI_VIDEO_S_DVI = 0x08,     /* DVI output enabled */
-};
-
-enum {  /* TPACPI_VIDEO_570 constants */
-       TP_ACPI_VIDEO_570_PHSCMD = 0x87,        /* unknown magic constant :( */
-       TP_ACPI_VIDEO_570_PHSMASK = 0x03,       /* PHS bits that map to
-                                                * video_status_flags */
-       TP_ACPI_VIDEO_570_PHS2CMD = 0x8b,       /* unknown magic constant :( */
-       TP_ACPI_VIDEO_570_PHS2SET = 0x80,       /* unknown magic constant :( */
-};
-
-static enum video_access_mode video_supported;
-static int video_orig_autosw;
-static acpi_handle vid_handle, vid2_handle;
-
-static int video_init(struct ibm_init_struct *iibm);
-static void video_exit(void);
-static int video_outputsw_get(void);
-static int video_outputsw_set(int status);
-static int video_autosw_get(void);
-static int video_autosw_set(int enable);
-static int video_outputsw_cycle(void);
-static int video_expand_toggle(void);
-static int video_read(char *p);
-static int video_write(char *buf);
-
-
-/*
- * Volume subdriver
- */
-
-static int volume_offset = 0x30;
-
-static int volume_read(char *p);
-static int volume_write(char *buf);
-
-
-/*
- * Wan subdriver
- */
-
-enum {
-       /* ACPI GWAN/SWAN bits */
-       TP_ACPI_WANCARD_HWPRESENT       = 0x01, /* Wan hw available */
-       TP_ACPI_WANCARD_RADIOSSW        = 0x02, /* Wan radio enabled */
-       TP_ACPI_WANCARD_UNK             = 0x04, /* unknown function */
-};
-
-static int wan_init(struct ibm_init_struct *iibm);
-static int wan_get_radiosw(void);
-static int wan_set_radiosw(int radio_on);
-static int wan_read(char *p);
-static int wan_write(char *buf);
-
-
-#endif /* __THINKPAD_ACPI_H */
index 8848e8ac705d9f22a35dce96d3fe788984cc52ed..e8503341e3b147f5bc242e640bb1596e261695e9 100644 (file)
@@ -150,6 +150,14 @@ config MTD_AFS_PARTS
          for your particular device. It won't happen automatically. The
          'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
 
+config MTD_OF_PARTS
+       tristate "Flash partition map based on OF description"
+       depends on PPC_OF && MTD_PARTITIONS
+       help
+         This provides a partition parsing function which derives
+         the partition map from the children of the flash node,
+         as described in Documentation/powerpc/booting-without-of.txt.
+
 comment "User Modules And Translation Layers"
 
 config MTD_CHAR
@@ -286,6 +294,9 @@ config MTD_OOPS
          buffer in a flash partition where it can be read back at some
          later point.
 
+         To use, add console=ttyMTDx to the kernel command line,
+         where x is the MTD device number to use.
+
 source "drivers/mtd/chips/Kconfig"
 
 source "drivers/mtd/maps/Kconfig"
index 7f0b04b4caa7b50e11cbbc8fe8b584f77c66ade4..538e33d11d46ce026265bc5c504b6c08222ee198 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_CONCAT)      += mtdconcat.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
 obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
 obj-$(CONFIG_MTD_AFS_PARTS)    += afs.o
+obj-$(CONFIG_MTD_OF_PARTS)      += ofpart.o
 
 # 'Users' - code which presents functionality to userspace.
 obj-$(CONFIG_MTD_CHAR)         += mtdchar.o
index 1707f98c322c589c144b59d19cd9a52cbb22377a..47794d23a42ec2029371f35cf71bea6eafd8f073 100644 (file)
@@ -50,6 +50,7 @@
 #define I82802AC       0x00ac
 #define MANUFACTURER_ST         0x0020
 #define M50LPW080       0x002F
+#define AT49BV640D     0x02de
 
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -157,6 +158,47 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
 }
 #endif
 
+/* Atmel chips don't use the same PRI format as Intel chips */
+static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+       struct cfi_pri_atmel atmel_pri;
+       uint32_t features = 0;
+
+       /* Reverse byteswapping */
+       extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport);
+       extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask);
+       extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr);
+
+       memcpy(&atmel_pri, extp, sizeof(atmel_pri));
+       memset((char *)extp + 5, 0, sizeof(*extp) - 5);
+
+       printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features);
+
+       if (atmel_pri.Features & 0x01) /* chip erase supported */
+               features |= (1<<0);
+       if (atmel_pri.Features & 0x02) /* erase suspend supported */
+               features |= (1<<1);
+       if (atmel_pri.Features & 0x04) /* program suspend supported */
+               features |= (1<<2);
+       if (atmel_pri.Features & 0x08) /* simultaneous operations supported */
+               features |= (1<<9);
+       if (atmel_pri.Features & 0x20) /* page mode read supported */
+               features |= (1<<7);
+       if (atmel_pri.Features & 0x40) /* queued erase supported */
+               features |= (1<<4);
+       if (atmel_pri.Features & 0x80) /* Protection bits supported */
+               features |= (1<<6);
+
+       extp->FeatureSupport = features;
+
+       /* burst write mode not supported */
+       cfi->cfiq->BufWriteTimeoutTyp = 0;
+       cfi->cfiq->BufWriteTimeoutMax = 0;
+}
+
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
 /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
 static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
@@ -227,13 +269,20 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
 /*
  * Some chips power-up with all sectors locked by default.
  */
-static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
+static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
 {
-       printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
-       mtd->flags |= MTD_STUPID_LOCK;
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+
+       if (cfip->FeatureSupport&32) {
+               printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
+               mtd->flags |= MTD_POWERUP_LOCK;
+       }
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
+       { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
        { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
 #endif
@@ -245,7 +294,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
 #endif
        { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
        { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
-       { MANUFACTURER_INTEL, 0x891c,         fixup_use_powerup_lock, NULL, },
+       { MANUFACTURER_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
        { 0, 0, NULL, NULL }
 };
 
@@ -277,7 +326,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                return NULL;
 
        if (extp->MajorVersion != '1' ||
-           (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
+           (extp->MinorVersion < '0' || extp->MinorVersion > '5')) {
                printk(KERN_ERR "  Unknown Intel/Sharp Extended Query "
                       "version %c.%c.\n",  extp->MajorVersion,
                       extp->MinorVersion);
@@ -752,6 +801,7 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
 {
        int ret;
+       DECLARE_WAITQUEUE(wait, current);
 
  retry:
        if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
@@ -808,6 +858,20 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                        spin_unlock(contender->mutex);
                }
 
+               /* Check if we already have suspended erase
+                * on this chip. Sleep. */
+               if (mode == FL_ERASING && shared->erasing
+                   && shared->erasing->oldstate == FL_ERASING) {
+                       spin_unlock(&shared->lock);
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       add_wait_queue(&chip->wq, &wait);
+                       spin_unlock(chip->mutex);
+                       schedule();
+                       remove_wait_queue(&chip->wq, &wait);
+                       spin_lock(chip->mutex);
+                       goto retry;
+               }
+
                /* We now own it */
                shared->writing = chip;
                if (mode == FL_ERASING)
@@ -2294,7 +2358,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
        struct flchip *chip;
        int ret = 0;
 
-       if ((mtd->flags & MTD_STUPID_LOCK)
+       if ((mtd->flags & MTD_POWERUP_LOCK)
            && extp && (extp->FeatureSupport & (1 << 5)))
                cfi_intelext_save_locks(mtd);
 
@@ -2405,7 +2469,7 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
                spin_unlock(chip->mutex);
        }
 
-       if ((mtd->flags & MTD_STUPID_LOCK)
+       if ((mtd->flags & MTD_POWERUP_LOCK)
            && extp && (extp->FeatureSupport & (1 << 5)))
                cfi_intelext_restore_locks(mtd);
 }
index 389acc600f5e9a214939f041a794e8382ff4c1d3..d072e87ce4e20cec96af6220d8bd903864b8de29 100644 (file)
@@ -185,6 +185,10 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
                extp->TopBottom = 2;
        else
                extp->TopBottom = 3;
+
+       /* burst write mode not supported */
+       cfi->cfiq->BufWriteTimeoutTyp = 0;
+       cfi->cfiq->BufWriteTimeoutMax = 0;
 }
 
 static void fixup_use_secsi(struct mtd_info *mtd, void *param)
@@ -213,10 +217,11 @@ static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param)
 {
        mtd->lock = cfi_atmel_lock;
        mtd->unlock = cfi_atmel_unlock;
-       mtd->flags |= MTD_STUPID_LOCK;
+       mtd->flags |= MTD_POWERUP_LOCK;
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
+       { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 #ifdef AMD_BOOTLOC_BUG
        { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
 #endif
@@ -229,7 +234,6 @@ static struct cfi_fixup cfi_fixup_table[] = {
 #if !FORCE_WORD_WRITE
        { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
 #endif
-       { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
        { 0, 0, NULL, NULL }
 };
 static struct cfi_fixup jedec_fixup_table[] = {
@@ -338,10 +342,12 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
                /* Modify the unlock address if we are in compatibility mode */
                if (    /* x16 in x8 mode */
                        ((cfi->device_type == CFI_DEVICETYPE_X8) &&
-                               (cfi->cfiq->InterfaceDesc == 2)) ||
+                               (cfi->cfiq->InterfaceDesc ==
+                                       CFI_INTERFACE_X8_BY_X16_ASYNC)) ||
                        /* x32 in x16 mode */
                        ((cfi->device_type == CFI_DEVICETYPE_X16) &&
-                               (cfi->cfiq->InterfaceDesc == 4)))
+                               (cfi->cfiq->InterfaceDesc ==
+                                       CFI_INTERFACE_X16_BY_X32_ASYNC)))
                {
                        cfi->addr_unlock1 = 0xaaa;
                        cfi->addr_unlock2 = 0x555;
index 60e11a0ada97b4d6ae9b1792eec64a45e6865da8..f651b6ef1c5d6c44805b066fab343eb965f952d0 100644 (file)
@@ -370,27 +370,27 @@ static void print_cfi_ident(struct cfi_ident *cfip)
        printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20));
        printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc);
        switch(cfip->InterfaceDesc) {
-       case 0:
+       case CFI_INTERFACE_X8_ASYNC:
                printk("  - x8-only asynchronous interface\n");
                break;
 
-       case 1:
+       case CFI_INTERFACE_X16_ASYNC:
                printk("  - x16-only asynchronous interface\n");
                break;
 
-       case 2:
+       case CFI_INTERFACE_X8_BY_X16_ASYNC:
                printk("  - supports x8 and x16 via BYTE# with asynchronous interface\n");
                break;
 
-       case 3:
+       case CFI_INTERFACE_X32_ASYNC:
                printk("  - x32-only asynchronous interface\n");
                break;
 
-       case 4:
+       case CFI_INTERFACE_X16_BY_X32_ASYNC:
                printk("  - supports x16 and x32 via Word# with asynchronous interface\n");
                break;
 
-       case 65535:
+       case CFI_INTERFACE_NOT_ALLOWED:
                printk("  - Not Allowed / Reserved\n");
                break;
 
index 2eb696d7b97b0ca61ebf61c29cdfdaa2b70a3a91..d338b8c92780255d9d71a62f9484010a0cac7b64 100644 (file)
@@ -112,7 +112,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
                max_chips = 1;
        }
 
-       mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG;
+       mapsize = sizeof(long) * ( (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG );
        chip_map = kzalloc(mapsize, GFP_KERNEL);
        if (!chip_map) {
                printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
index a67b23b87fc044ecad43173e7c76bc9b025e0910..4be51a86a85cbbe711eaca3973ab9716692735ae 100644 (file)
@@ -194,8 +194,8 @@ enum uaddr {
 
 
 struct unlock_addr {
-       u32 addr1;
-       u32 addr2;
+       uint32_t addr1;
+       uint32_t addr2;
 };
 
 
@@ -246,16 +246,16 @@ static const struct unlock_addr  unlock_addrs[] = {
        }
 };
 
-
 struct amd_flash_info {
-       const __u16 mfr_id;
-       const __u16 dev_id;
        const char *name;
-       const int DevSize;
-       const int NumEraseRegions;
-       const int CmdSet;
-       const __u8 uaddr[4];            /* unlock addrs for 8, 16, 32, 64 */
-       const ulong regions[6];
+       const uint16_t mfr_id;
+       const uint16_t dev_id;
+       const uint8_t dev_size;
+       const uint8_t nr_regions;
+       const uint16_t cmd_set;
+       const uint32_t regions[6];
+       const uint8_t devtypes;         /* Bitmask for x8, x16 etc. */
+       const uint8_t uaddr;            /* unlock addrs for 8, 16, 32, 64 */
 };
 
 #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
@@ -280,12 +280,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F032B,
                .name           = "AMD AM29F032B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,64)
                }
@@ -293,13 +292,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV160DT,
                .name           = "AMD AM29LV160DT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -310,13 +307,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV160DB,
                .name           = "AMD AM29LV160DB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -327,13 +322,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV400BB,
                .name           = "AMD AM29LV400BB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -344,13 +337,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV400BT,
                .name           = "AMD AM29LV400BT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,7),
                        ERASEINFO(0x08000,1),
@@ -361,13 +352,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV800BB,
                .name           = "AMD AM29LV800BB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -379,13 +368,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29DL800BB,
                .name           = "AMD AM29DL800BB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 6,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 6,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x08000,1),
@@ -398,13 +385,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29DL800BT,
                .name           = "AMD AM29DL800BT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 6,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 6,
                .regions        = {
                        ERASEINFO(0x10000,14),
                        ERASEINFO(0x04000,1),
@@ -417,13 +402,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F800BB,
                .name           = "AMD AM29F800BB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -434,13 +417,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV800BT,
                .name           = "AMD AM29LV800BT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,15),
                        ERASEINFO(0x08000,1),
@@ -451,13 +432,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F800BT,
                .name           = "AMD AM29F800BT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,15),
                        ERASEINFO(0x08000,1),
@@ -468,12 +447,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F017D,
                .name           = "AMD AM29F017D",
-               .uaddr          = {
-                       [0] = MTD_UADDR_DONT_CARE     /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_DONT_CARE,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -481,12 +459,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F016D,
                .name           = "AMD AM29F016D",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -494,12 +471,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F080,
                .name           = "AMD AM29F080",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -507,12 +483,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F040,
                .name           = "AMD AM29F040",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -520,12 +495,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV040B,
                .name           = "AMD AM29LV040B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -533,12 +507,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F002T,
                .name           = "AMD AM29F002T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,3),
                        ERASEINFO(0x08000,1),
@@ -549,12 +522,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV512,
                .name           = "Atmel AT49BV512",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_64KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_64KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,1)
                }
@@ -562,12 +534,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT29LV512,
                .name           = "Atmel AT29LV512",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_64KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_64KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x80,256),
                        ERASEINFO(0x80,256)
@@ -576,13 +547,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV16X,
                .name           = "Atmel AT49BV16X",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x0AAA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,31)
@@ -591,13 +560,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV16XT,
                .name           = "Atmel AT49BV16XT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x0AAA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x02000,8)
@@ -606,13 +573,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV32X,
                .name           = "Atmel AT49BV32X",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x0AAA,      /* ???? */
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,63)
@@ -621,13 +586,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV32XT,
                .name           = "Atmel AT49BV32XT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x0AAA,      /* ???? */
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,63),
                        ERASEINFO(0x02000,8)
@@ -636,12 +599,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29F040C,
                .name           = "Fujitsu MBM29F040C",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8)
                }
@@ -649,13 +611,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29F800BA,
                .name           = "Fujitsu MBM29F800BA",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -666,12 +626,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV650UE,
                .name           = "Fujitsu MBM29LV650UE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_DONT_CARE     /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_DONT_CARE,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,128)
                }
@@ -679,13 +638,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV320TE,
                .name           = "Fujitsu MBM29LV320TE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,63),
                        ERASEINFO(0x02000,8)
@@ -694,13 +651,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV320BE,
                .name           = "Fujitsu MBM29LV320BE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,63)
@@ -709,13 +664,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV160TE,
                .name           = "Fujitsu MBM29LV160TE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -726,13 +679,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV160BE,
                .name           = "Fujitsu MBM29LV160BE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -743,13 +694,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV800BA,
                .name           = "Fujitsu MBM29LV800BA",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -760,13 +709,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV800TA,
                .name           = "Fujitsu MBM29LV800TA",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,15),
                        ERASEINFO(0x08000,1),
@@ -777,13 +724,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV400BC,
                .name           = "Fujitsu MBM29LV400BC",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -794,13 +739,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV400TC,
                .name           = "Fujitsu MBM29LV400TC",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,7),
                        ERASEINFO(0x08000,1),
@@ -811,12 +754,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_HYUNDAI,
                .dev_id         = HY29F002T,
                .name           = "Hyundai HY29F002T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,3),
                        ERASEINFO(0x08000,1),
@@ -827,12 +769,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F004B3B,
                .name           = "Intel 28F004B3B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 7),
@@ -841,12 +782,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F004B3T,
                .name           = "Intel 28F004B3T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 7),
                        ERASEINFO(0x02000, 8),
@@ -855,13 +795,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F400B3B,
                .name           = "Intel 28F400B3B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 7),
@@ -870,13 +808,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F400B3T,
                .name           = "Intel 28F400B3T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 7),
                        ERASEINFO(0x02000, 8),
@@ -885,12 +821,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F008B3B,
                .name           = "Intel 28F008B3B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 15),
@@ -899,12 +834,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F008B3T,
                .name           = "Intel 28F008B3T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 15),
                        ERASEINFO(0x02000, 8),
@@ -913,12 +847,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F008S5,
                .name           = "Intel 28F008S5",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -926,12 +859,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F016S5,
                .name           = "Intel 28F016S5",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -939,12 +871,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F008SA,
                .name           = "Intel 28F008SA",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000, 16),
                }
@@ -952,12 +883,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F800B3B,
                .name           = "Intel 28F800B3B",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 15),
@@ -966,12 +896,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F800B3T,
                .name           = "Intel 28F800B3T",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 15),
                        ERASEINFO(0x02000, 8),
@@ -980,12 +909,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F016B3B,
                .name           = "Intel 28F016B3B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 31),
@@ -994,12 +922,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F016S3,
                .name           = "Intel I28F016S3",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000, 32),
                }
@@ -1007,12 +934,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F016B3T,
                .name           = "Intel 28F016B3T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 31),
                        ERASEINFO(0x02000, 8),
@@ -1021,12 +947,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F160B3B,
                .name           = "Intel 28F160B3B",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 31),
@@ -1035,12 +960,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F160B3T,
                .name           = "Intel 28F160B3T",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 31),
                        ERASEINFO(0x02000, 8),
@@ -1049,12 +973,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F320B3B,
                .name           = "Intel 28F320B3B",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 63),
@@ -1063,12 +986,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F320B3T,
                .name           = "Intel 28F320B3T",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 63),
                        ERASEINFO(0x02000, 8),
@@ -1077,12 +999,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F640B3B,
                .name           = "Intel 28F640B3B",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 127),
@@ -1091,12 +1012,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F640B3T,
                .name           = "Intel 28F640B3T",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 127),
                        ERASEINFO(0x02000, 8),
@@ -1105,12 +1025,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I82802AB,
                .name           = "Intel 82802AB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1118,12 +1037,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I82802AC,
                .name           = "Intel 82802AC",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -1131,12 +1049,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29LV040C,
                .name           = "Macronix MX29LV040C",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1144,13 +1061,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29LV160T,
                .name           = "MXIC MX29LV160T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -1161,13 +1076,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_NEC,
                .dev_id         = UPD29F064115,
                .name           = "NEC uPD29F064115",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 3,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,      /* ???? */
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 3,
                .regions        = {
                        ERASEINFO(0x2000,8),
                        ERASEINFO(0x10000,126),
@@ -1177,13 +1090,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29LV160B,
                .name           = "MXIC MX29LV160B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1194,12 +1105,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F040,
                .name           = "Macronix MX29F040",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1207,12 +1117,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F016,
                .name           = "Macronix MX29F016",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -1220,12 +1129,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F004T,
                .name           = "Macronix MX29F004T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,7),
                        ERASEINFO(0x08000,1),
@@ -1236,12 +1144,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F004B,
                .name           = "Macronix MX29F004B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1252,12 +1159,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F002T,
                .name           = "Macronix MX29F002T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,3),
                        ERASEINFO(0x08000,1),
@@ -1268,12 +1174,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_PMC,
                .dev_id         = PM49FL002,
                .name           = "PMC Pm49FL002",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO( 0x01000, 64 )
                }
@@ -1281,12 +1186,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_PMC,
                .dev_id         = PM49FL004,
                .name           = "PMC Pm49FL004",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO( 0x01000, 128 )
                }
@@ -1294,12 +1198,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_PMC,
                .dev_id         = PM49FL008,
                .name           = "PMC Pm49FL008",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO( 0x01000, 256 )
                }
@@ -1307,25 +1210,23 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SHARP,
                .dev_id         = LH28F640BF,
                .name           = "LH28F640BF",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 1,
-               .regions        = {
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 1,
+               .regions        = {
                        ERASEINFO(0x40000,16),
                }
         }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF512,
                .name           = "SST 39LF512",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_64KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_64KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,16),
                }
@@ -1333,12 +1234,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF010,
                .name           = "SST 39LF010",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_128KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_128KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,32),
                }
@@ -1346,36 +1246,33 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST29EE020,
                .name           = "SST 29EE020",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_SST_PAGE,
-               .NumEraseRegions= 1,
-               .regions = {ERASEINFO(0x01000,64),
-               }
-         }, {
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_SST_PAGE,
+               .nr_regions     = 1,
+               .regions = {ERASEINFO(0x01000,64),
+               }
+       }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST29LE020,
                .name           = "SST 29LE020",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_SST_PAGE,
-               .NumEraseRegions= 1,
-               .regions = {ERASEINFO(0x01000,64),
-               }
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_SST_PAGE,
+               .nr_regions     = 1,
+               .regions = {ERASEINFO(0x01000,64),
+               }
        }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF020,
                .name           = "SST 39LF020",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,64),
                }
@@ -1383,12 +1280,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF040,
                .name           = "SST 39LF040",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,128),
                }
@@ -1396,12 +1292,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39SF010A,
                .name           = "SST 39SF010A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_128KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_128KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,32),
                }
@@ -1409,26 +1304,24 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39SF020A,
                .name           = "SST 39SF020A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,64),
                }
        }, {
                .mfr_id         = MANUFACTURER_SST,
-               .dev_id         = SST49LF040B,
-               .name           = "SST 49LF040B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
-               .regions        = {
+               .dev_id         = SST49LF040B,
+               .name           = "SST 49LF040B",
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
+               .regions        = {
                        ERASEINFO(0x01000,128),
                }
        }, {
@@ -1436,12 +1329,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF004B,
                .name           = "SST 49LF004B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,128),
                }
@@ -1449,12 +1341,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF008A,
                .name           = "SST 49LF008A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,256),
                }
@@ -1462,12 +1353,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF030A,
                .name           = "SST 49LF030A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,96),
                }
@@ -1475,12 +1365,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF040A,
                .name           = "SST 49LF040A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,128),
                }
@@ -1488,57 +1377,49 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF080A,
                .name           = "SST 49LF080A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,256),
                }
        }, {
-               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
-               .dev_id         = SST39LF160,
-               .name           = "SST 39LF160",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
-               .regions        = {
-                       ERASEINFO(0x1000,256),
-                       ERASEINFO(0x1000,256)
-               }
-       }, {
-               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
-               .dev_id         = SST39VF1601,
-               .name           = "SST 39VF1601",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
-               .regions        = {
-                       ERASEINFO(0x1000,256),
-                       ERASEINFO(0x1000,256)
-               }
-
+               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
+               .dev_id         = SST39LF160,
+               .name           = "SST 39LF160",
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
+               .regions        = {
+                       ERASEINFO(0x1000,256),
+                       ERASEINFO(0x1000,256)
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
+               .dev_id         = SST39VF1601,
+               .name           = "SST 39VF1601",
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
+               .regions        = {
+                       ERASEINFO(0x1000,256),
+                       ERASEINFO(0x1000,256)
+               }
        }, {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M29F800AB,
                .name           = "ST M29F800AB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1549,13 +1430,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
                .dev_id         = M29W800DT,
                .name           = "ST M29W800DT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,      /* ???? */
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,15),
                        ERASEINFO(0x08000,1),
@@ -1566,13 +1445,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
                .dev_id         = M29W800DB,
                .name           = "ST M29W800DB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,      /* ???? */
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1583,13 +1460,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
                .dev_id         = M29W160DT,
                .name           = "ST M29W160DT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -1600,13 +1475,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
                .dev_id         = M29W160DB,
                .name           = "ST M29W160DB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1617,12 +1490,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M29W040B,
                .name           = "ST M29W040B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1630,12 +1502,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M50FW040,
                .name           = "ST M50FW040",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1643,12 +1514,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M50FW080,
                .name           = "ST M50FW080",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -1656,12 +1526,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M50FW016,
                .name           = "ST M50FW016",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -1669,12 +1538,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M50LPW080,
                .name           = "ST M50LPW080",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -1682,13 +1550,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVT160,
                .name           = "Toshiba TC58FVT160",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -1699,13 +1565,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVB160,
                .name           = "Toshiba TC58FVB160",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1716,13 +1580,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVB321,
                .name           = "Toshiba TC58FVB321",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,63)
@@ -1731,13 +1593,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVT321,
                .name           = "Toshiba TC58FVT321",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,63),
                        ERASEINFO(0x02000,8)
@@ -1746,13 +1606,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVB641,
                .name           = "Toshiba TC58FVB641",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,127)
@@ -1761,13 +1619,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVT641,
                .name           = "Toshiba TC58FVT641",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,127),
                        ERASEINFO(0x02000,8)
@@ -1776,12 +1632,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_WINBOND,
                .dev_id         = W49V002A,
                .name           = "Winbond W49V002A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000, 3),
                        ERASEINFO(0x08000, 1),
@@ -1791,15 +1646,7 @@ static const struct amd_flash_info jedec_table[] = {
        }
 };
 
-
-static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
-
-static int jedec_probe_chip(struct map_info *map, __u32 base,
-                           unsigned long *chip_map, struct cfi_private *cfi);
-
-static struct mtd_info *jedec_probe(struct map_info *map);
-
-static inline u32 jedec_read_mfr(struct map_info *map, __u32 base,
+static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base,
        struct cfi_private *cfi)
 {
        map_word result;
@@ -1810,7 +1657,7 @@ static inline u32 jedec_read_mfr(struct map_info *map, __u32 base,
        return result.x[0] & mask;
 }
 
-static inline u32 jedec_read_id(struct map_info *map, __u32 base,
+static inline u32 jedec_read_id(struct map_info *map, uint32_t base,
        struct cfi_private *cfi)
 {
        map_word result;
@@ -1821,8 +1668,7 @@ static inline u32 jedec_read_id(struct map_info *map, __u32 base,
        return result.x[0] & mask;
 }
 
-static inline void jedec_reset(u32 base, struct map_info *map,
-       struct cfi_private *cfi)
+static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi)
 {
        /* Reset */
 
@@ -1832,7 +1678,7 @@ static inline void jedec_reset(u32 base, struct map_info *map,
         * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips
         * as they will ignore the writes and dont care what address
         * the F0 is written to */
-       if(cfi->addr_unlock1) {
+       if (cfi->addr_unlock1) {
                DEBUG( MTD_DEBUG_LEVEL3,
                       "reset unlock called %x %x \n",
                       cfi->addr_unlock1,cfi->addr_unlock2);
@@ -1841,7 +1687,7 @@ static inline void jedec_reset(u32 base, struct map_info *map,
        }
 
        cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-       /* Some misdesigned intel chips do not respond for 0xF0 for a reset,
+       /* Some misdesigned Intel chips do not respond for 0xF0 for a reset,
         * so ensure we're in read mode.  Send both the Intel and the AMD command
         * for this.  Intel uses 0xff for this, AMD uses 0xff for NOP, so
         * this should be safe.
@@ -1851,42 +1697,20 @@ static inline void jedec_reset(u32 base, struct map_info *map,
 }
 
 
-static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_type)
-{
-       int uaddr_idx;
-       __u8 uaddr = MTD_UADDR_NOT_SUPPORTED;
-
-       switch ( device_type ) {
-       case CFI_DEVICETYPE_X8:  uaddr_idx = 0; break;
-       case CFI_DEVICETYPE_X16: uaddr_idx = 1; break;
-       case CFI_DEVICETYPE_X32: uaddr_idx = 2; break;
-       default:
-               printk(KERN_NOTICE "MTD: %s(): unknown device_type %d\n",
-                      __func__, device_type);
-               goto uaddr_done;
-       }
-
-       uaddr = finfo->uaddr[uaddr_idx];
-
-       if (uaddr != MTD_UADDR_NOT_SUPPORTED ) {
-               /* ASSERT("The unlock addresses for non-8-bit mode
-                  are bollocks. We don't really need an array."); */
-               uaddr = finfo->uaddr[0];
-       }
-
- uaddr_done:
-       return uaddr;
-}
-
-
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 {
        int i,num_erase_regions;
-       __u8 uaddr;
+       uint8_t uaddr;
 
-       printk("Found: %s\n",jedec_table[index].name);
+       if (! (jedec_table[index].devtypes & p_cfi->device_type)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "Rejecting potential %s with incompatible %d-bit device type\n",
+                     jedec_table[index].name, 4 * (1<<p_cfi->device_type));
+               return 0;
+       }
+
+       printk(KERN_INFO "Found: %s\n",jedec_table[index].name);
 
-       num_erase_regions = jedec_table[index].NumEraseRegions;
+       num_erase_regions = jedec_table[index].nr_regions;
 
        p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
        if (!p_cfi->cfiq) {
@@ -1896,9 +1720,9 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 
        memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));
 
-       p_cfi->cfiq->P_ID = jedec_table[index].CmdSet;
-       p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions;
-       p_cfi->cfiq->DevSize = jedec_table[index].DevSize;
+       p_cfi->cfiq->P_ID = jedec_table[index].cmd_set;
+       p_cfi->cfiq->NumEraseRegions = jedec_table[index].nr_regions;
+       p_cfi->cfiq->DevSize = jedec_table[index].dev_size;
        p_cfi->cfi_mode = CFI_MODE_JEDEC;
 
        for (i=0; i<num_erase_regions; i++){
@@ -1910,14 +1734,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
        p_cfi->mfr = jedec_table[index].mfr_id;
        p_cfi->id = jedec_table[index].dev_id;
 
-       uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type);
-       if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
-               kfree( p_cfi->cfiq );
-               return 0;
-       }
+       uaddr = jedec_table[index].uaddr;
 
-       p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
-       p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
+       /* The table has unlock addresses in _bytes_, and we try not to let
+          our brains explode when we see the datasheets talking about address
+          lines numbered from A-1 to A18. The CFI table has unlock addresses
+          in device-words according to the mode the device is connected in */
+       p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 / p_cfi->device_type;
+       p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 / p_cfi->device_type;
 
        return 1;       /* ok */
 }
@@ -1930,14 +1754,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
  * be perfect - consequently there should be some module parameters that
  * could be manually specified to force the chip info.
  */
-static inline int jedec_match( __u32 base,
+static inline int jedec_match( uint32_t base,
                               struct map_info *map,
                               struct cfi_private *cfi,
                               const struct amd_flash_info *finfo )
 {
        int rc = 0;           /* failure until all tests pass */
        u32 mfr, id;
-       __u8 uaddr;
+       uint8_t uaddr;
 
        /*
         * The IDs must match.  For X16 and X32 devices operating in
@@ -1950,8 +1774,8 @@ static inline int jedec_match( __u32 base,
         */
        switch (cfi->device_type) {
        case CFI_DEVICETYPE_X8:
-               mfr = (__u8)finfo->mfr_id;
-               id = (__u8)finfo->dev_id;
+               mfr = (uint8_t)finfo->mfr_id;
+               id = (uint8_t)finfo->dev_id;
 
                /* bjd: it seems that if we do this, we can end up
                 * detecting 16bit flashes as an 8bit device, even though
@@ -1964,12 +1788,12 @@ static inline int jedec_match( __u32 base,
                }
                break;
        case CFI_DEVICETYPE_X16:
-               mfr = (__u16)finfo->mfr_id;
-               id = (__u16)finfo->dev_id;
+               mfr = (uint16_t)finfo->mfr_id;
+               id = (uint16_t)finfo->dev_id;
                break;
        case CFI_DEVICETYPE_X32:
-               mfr = (__u16)finfo->mfr_id;
-               id = (__u32)finfo->dev_id;
+               mfr = (uint16_t)finfo->mfr_id;
+               id = (uint32_t)finfo->dev_id;
                break;
        default:
                printk(KERN_WARNING
@@ -1984,25 +1808,25 @@ static inline int jedec_match( __u32 base,
        /* the part size must fit in the memory window */
        DEBUG( MTD_DEBUG_LEVEL3,
               "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n",
-              __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) );
-       if ( base + cfi_interleave(cfi) * ( 1 << finfo->DevSize ) > map->size ) {
+              __func__, base, 1 << finfo->dev_size, base + (1 << finfo->dev_size) );
+       if ( base + cfi_interleave(cfi) * ( 1 << finfo->dev_size ) > map->size ) {
                DEBUG( MTD_DEBUG_LEVEL3,
                       "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n",
                       __func__, finfo->mfr_id, finfo->dev_id,
-                      1 << finfo->DevSize );
+                      1 << finfo->dev_size );
                goto match_done;
        }
 
-       uaddr = finfo_uaddr(finfo, cfi->device_type);
-       if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
+       if (! (finfo->devtypes & cfi->device_type))
                goto match_done;
-       }
+
+       uaddr = finfo->uaddr;
 
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n",
               __func__, cfi->addr_unlock1, cfi->addr_unlock2 );
        if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr
-            && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1 ||
-                 unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) {
+            && ( unlock_addrs[uaddr].addr1 / cfi->device_type != cfi->addr_unlock1 ||
+                 unlock_addrs[uaddr].addr2 / cfi->device_type != cfi->addr_unlock2 ) ) {
                DEBUG( MTD_DEBUG_LEVEL3,
                        "MTD %s(): 0x%.4x 0x%.4x did not match\n",
                        __func__,
@@ -2042,7 +1866,7 @@ static inline int jedec_match( __u32 base,
         * were truly frobbing a real device.
         */
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ );
-       if(cfi->addr_unlock1) {
+       if (cfi->addr_unlock1) {
                cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
                cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
        }
@@ -2068,8 +1892,8 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                if (MTD_UADDR_UNNECESSARY == uaddr_idx)
                        return 0;
 
-               cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
-               cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
+               cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 / cfi->device_type;
+               cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 / cfi->device_type;
        }
 
        /* Make certain we aren't probing past the end of map */
@@ -2081,19 +1905,11 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
 
        }
        /* Ensure the unlock addresses we try stay inside the map */
-       probe_offset1 = cfi_build_cmd_addr(
-               cfi->addr_unlock1,
-               cfi_interleave(cfi),
-               cfi->device_type);
-       probe_offset2 = cfi_build_cmd_addr(
-               cfi->addr_unlock1,
-               cfi_interleave(cfi),
-               cfi->device_type);
+       probe_offset1 = cfi_build_cmd_addr(cfi->addr_unlock1, cfi_interleave(cfi), cfi->device_type);
+       probe_offset2 = cfi_build_cmd_addr(cfi->addr_unlock2, cfi_interleave(cfi), cfi->device_type);
        if (    ((base + probe_offset1 + map_bankwidth(map)) >= map->size) ||
                ((base + probe_offset2 + map_bankwidth(map)) >= map->size))
-       {
                goto retry;
-       }
 
        /* Reset */
        jedec_reset(base, map, cfi);
@@ -2128,8 +1944,8 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                }
                goto retry;
        } else {
-               __u16 mfr;
-               __u16 id;
+               uint16_t mfr;
+               uint16_t id;
 
                /* Make sure it is a chip of the same manufacturer and id */
                mfr = jedec_read_mfr(map, base, cfi);
index 23fab14f1637cab5fb4ee175ff5eaea6db141915..b44292abd9f7bd68c94228ac11200b3549dc1711 100644 (file)
@@ -9,7 +9,7 @@
  *
  * mtdparts=<mtddef>[;<mtddef]
  * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
- * <partdef> := <size>[@offset][<name>][ro]
+ * <partdef> := <size>[@offset][<name>][ro][lk]
  * <mtd-id>  := unique name used in mapping driver/device (mtd->name)
  * <size>    := standard linux memsize OR "-" to denote all remaining space
  * <name>    := '(' NAME ')'
@@ -143,6 +143,13 @@ static struct mtd_partition * newpart(char *s,
                s += 2;
         }
 
+        /* if lk is found do NOT unlock the MTD partition*/
+        if (strncmp(s, "lk", 2) == 0)
+       {
+               mask_flags |= MTD_POWERUP_LOCK;
+               s += 2;
+        }
+
        /* test if more partitions are following */
        if (*s == ',')
        {
index 90acf57c19bd29962197cf9ed83fa332e3888a4c..846989f292e3f01a1992dd73f999583263b9ec7f 100644 (file)
@@ -632,7 +632,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
                        len = ((from | 0x1ff) + 1) - from;
 
                /* The ECC will not be calculated correctly if less than 512 is read */
-               if (len != 0x200 && eccbuf)
+               if (len != 0x200)
                        printk(KERN_WARNING
                               "ECC needs a full sector read (adr: %lx size %lx)\n",
                               (long) from, (long) len);
@@ -896,7 +896,7 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
                /* Let the caller know we completed it */
                *retlen += len;
 
-               if (eccbuf) {
+               {
                        unsigned char x[8];
                        size_t dummy;
                        int ret;
index 2b30b587c6e840c0e820a9a30aff74ba40f90f3c..83be3461658f22527a40ab1e57ec0efa503c8252 100644 (file)
@@ -748,7 +748,7 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
        WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd);
 
        /* On interleaved devices the flags for 2nd half 512 are before data */
-       if (eccbuf && before)
+       if (before)
                fto -= 2;
 
        /* issue the Serial Data In command to initial the Page Program process */
index 4ea50a1dda8570a1606abbbd623c93f011df2bb7..99fd210feaece71fa8f39658e3fa16d4bdebdcfb 100644 (file)
@@ -323,7 +323,7 @@ static int flash_probe (void)
    /* put the flash back into command mode */
    write32 (DATA_TO_FLASH (READ_ARRAY),0x00000000);
 
-   return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || FLASH_DEVICE_16mbit_BOTTOM));
+   return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || devtype == FLASH_DEVICE_16mbit_BOTTOM));
 }
 
 /*
index a5ed6d232c357b16b7ffacfedd10d81a9915dad8..b35e4813a3a5e146f6725fb13d6d3be0f588bfe6 100644 (file)
@@ -420,7 +420,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
                status = dataflash_waitready(priv->spi);
 
                /* Check result of the compare operation */
-               if ((status & (1 << 6)) == 1) {
+               if (status & (1 << 6)) {
                        printk(KERN_ERR "%s: compare page %u, err %d\n",
                                spi->dev.bus_id, pageaddr, status);
                        remaining = 0;
index a592fc04cf781455459bbb390227da7f72fdab50..12c253664eb223e524d31b2fb6bc800f9286cd44 100644 (file)
@@ -110,13 +110,6 @@ config MTD_SUN_UFLASH
          Sun Microsystems boardsets.  This driver will require CFI support
          in the kernel, so if you did not enable CFI previously, do that now.
 
-config MTD_PNC2000
-       tristate "CFI Flash device mapped on Photron PNC-2000"
-       depends on X86 && MTD_CFI && MTD_PARTITIONS
-       help
-         PNC-2000 is the name of Network Camera product from PHOTRON
-         Ltd. in Japan. It uses CFI-compliant flash.
-
 config MTD_SC520CDP
        tristate "CFI Flash device mapped on AMD SC520 CDP"
        depends on X86 && MTD_CFI && MTD_CONCAT
@@ -576,7 +569,7 @@ config MTD_BAST_MAXSIZE
        default "4"
 
 config MTD_SHARP_SL
-       bool "ROM mapped on Sharp SL Series"
+       tristate "ROM mapped on Sharp SL Series"
        depends on ARCH_PXA
        help
          This enables access to the flash chip on the Sharp SL Series of PDAs.
index 316382a1401be8dced078b5e2736322a08c637f8..a9cbe80f99a0d909eec2f89e109dfd53a7365a50 100644 (file)
@@ -28,7 +28,6 @@ obj-$(CONFIG_MTD_PHYSMAP)     += physmap.o
 obj-$(CONFIG_MTD_PHYSMAP_OF)   += physmap_of.o
 obj-$(CONFIG_MTD_PMC_MSP_EVM)   += pmcmsp-flash.o
 obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o
-obj-$(CONFIG_MTD_PNC2000)      += pnc2000.o
 obj-$(CONFIG_MTD_PCMCIA)       += pcmciamtd.o
 obj-$(CONFIG_MTD_RPXLITE)      += rpxlite.o
 obj-$(CONFIG_MTD_TQM8XXL)      += tqm8xxl.o
index 28c5ffd75233a27fd8dd40ba23cf739fe5710f69..f00e04efbe2898db97673008c90f5faea20e1fa6 100644 (file)
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/mtd/concat.h>
 #include <asm/io.h>
 
+#define MAX_RESOURCES          4
+
 struct physmap_flash_info {
-       struct mtd_info         *mtd;
-       struct map_info         map;
+       struct mtd_info         *mtd[MAX_RESOURCES];
+       struct mtd_info         *cmtd;
+       struct map_info         map[MAX_RESOURCES];
        struct resource         *res;
 #ifdef CONFIG_MTD_PARTITIONS
        int                     nr_parts;
@@ -32,11 +36,11 @@ struct physmap_flash_info {
 #endif
 };
 
-
 static int physmap_flash_remove(struct platform_device *dev)
 {
        struct physmap_flash_info *info;
        struct physmap_flash_data *physmap_data;
+       int i;
 
        info = platform_get_drvdata(dev);
        if (info == NULL)
@@ -45,24 +49,33 @@ static int physmap_flash_remove(struct platform_device *dev)
 
        physmap_data = dev->dev.platform_data;
 
-       if (info->mtd != NULL) {
+#ifdef CONFIG_MTD_CONCAT
+       if (info->cmtd != info->mtd[0]) {
+               del_mtd_device(info->cmtd);
+               mtd_concat_destroy(info->cmtd);
+       }
+#endif
+
+       for (i = 0; i < MAX_RESOURCES; i++) {
+               if (info->mtd[i] != NULL) {
 #ifdef CONFIG_MTD_PARTITIONS
-               if (info->nr_parts) {
-                       del_mtd_partitions(info->mtd);
-                       kfree(info->parts);
-               } else if (physmap_data->nr_parts) {
-                       del_mtd_partitions(info->mtd);
-               } else {
-                       del_mtd_device(info->mtd);
-               }
+                       if (info->nr_parts) {
+                               del_mtd_partitions(info->mtd[i]);
+                               kfree(info->parts);
+                       } else if (physmap_data->nr_parts) {
+                               del_mtd_partitions(info->mtd[i]);
+                       } else {
+                               del_mtd_device(info->mtd[i]);
+                       }
 #else
-               del_mtd_device(info->mtd);
+                       del_mtd_device(info->mtd[i]);
 #endif
-               map_destroy(info->mtd);
-       }
+                       map_destroy(info->mtd[i]);
+               }
 
-       if (info->map.virt != NULL)
-               iounmap(info->map.virt);
+               if (info->map[i].virt != NULL)
+                       iounmap(info->map[i].virt);
+       }
 
        if (info->res != NULL) {
                release_resource(info->res);
@@ -82,16 +95,14 @@ static int physmap_flash_probe(struct platform_device *dev)
        struct physmap_flash_data *physmap_data;
        struct physmap_flash_info *info;
        const char **probe_type;
-       int err;
+       int err = 0;
+       int i;
+       int devices_found = 0;
 
        physmap_data = dev->dev.platform_data;
        if (physmap_data == NULL)
                return -ENODEV;
 
-               printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
-           (unsigned long long)(dev->resource->end - dev->resource->start + 1),
-           (unsigned long long)dev->resource->start);
-
        info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
        if (info == NULL) {
                err = -ENOMEM;
@@ -100,56 +111,83 @@ static int physmap_flash_probe(struct platform_device *dev)
 
        platform_set_drvdata(dev, info);
 
-       info->res = request_mem_region(dev->resource->start,
-                       dev->resource->end - dev->resource->start + 1,
-                       dev->dev.bus_id);
-       if (info->res == NULL) {
-               dev_err(&dev->dev, "Could not reserve memory region\n");
-               err = -ENOMEM;
-               goto err_out;
-       }
+       for (i = 0; i < dev->num_resources; i++) {
+               printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
+                      (unsigned long long)(dev->resource[i].end - dev->resource[i].start + 1),
+                      (unsigned long long)dev->resource[i].start);
+
+               info->res = request_mem_region(dev->resource[i].start,
+                                              dev->resource[i].end - dev->resource[i].start + 1,
+                                              dev->dev.bus_id);
+               if (info->res == NULL) {
+                       dev_err(&dev->dev, "Could not reserve memory region\n");
+                       err = -ENOMEM;
+                       goto err_out;
+               }
 
-       info->map.name = dev->dev.bus_id;
-       info->map.phys = dev->resource->start;
-       info->map.size = dev->resource->end - dev->resource->start + 1;
-       info->map.bankwidth = physmap_data->width;
-       info->map.set_vpp = physmap_data->set_vpp;
+               info->map[i].name = dev->dev.bus_id;
+               info->map[i].phys = dev->resource[i].start;
+               info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1;
+               info->map[i].bankwidth = physmap_data->width;
+               info->map[i].set_vpp = physmap_data->set_vpp;
+
+               info->map[i].virt = ioremap(info->map[i].phys, info->map[i].size);
+               if (info->map[i].virt == NULL) {
+                       dev_err(&dev->dev, "Failed to ioremap flash region\n");
+                       err = EIO;
+                       goto err_out;
+               }
 
-       info->map.virt = ioremap(info->map.phys, info->map.size);
-       if (info->map.virt == NULL) {
-               dev_err(&dev->dev, "Failed to ioremap flash region\n");
-               err = EIO;
-               goto err_out;
-       }
+               simple_map_init(&info->map[i]);
 
-       simple_map_init(&info->map);
+               probe_type = rom_probe_types;
+               for (; info->mtd[i] == NULL && *probe_type != NULL; probe_type++)
+                       info->mtd[i] = do_map_probe(*probe_type, &info->map[i]);
+               if (info->mtd[i] == NULL) {
+                       dev_err(&dev->dev, "map_probe failed\n");
+                       err = -ENXIO;
+                       goto err_out;
+               } else {
+                       devices_found++;
+               }
+               info->mtd[i]->owner = THIS_MODULE;
+       }
 
-       probe_type = rom_probe_types;
-       for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
-               info->mtd = do_map_probe(*probe_type, &info->map);
-       if (info->mtd == NULL) {
-               dev_err(&dev->dev, "map_probe failed\n");
+       if (devices_found == 1) {
+               info->cmtd = info->mtd[0];
+       } else if (devices_found > 1) {
+               /*
+                * We detected multiple devices. Concatenate them together.
+                */
+#ifdef CONFIG_MTD_CONCAT
+               info->cmtd = mtd_concat_create(info->mtd, devices_found, dev->dev.bus_id);
+               if (info->cmtd == NULL)
+                       err = -ENXIO;
+#else
+               printk(KERN_ERR "physmap-flash: multiple devices "
+                      "found but MTD concat support disabled.\n");
                err = -ENXIO;
-               goto err_out;
+#endif
        }
-       info->mtd->owner = THIS_MODULE;
+       if (err)
+               goto err_out;
 
 #ifdef CONFIG_MTD_PARTITIONS
-       err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0);
+       err = parse_mtd_partitions(info->cmtd, part_probe_types, &info->parts, 0);
        if (err > 0) {
-               add_mtd_partitions(info->mtd, info->parts, err);
+               add_mtd_partitions(info->cmtd, info->parts, err);
                return 0;
        }
 
        if (physmap_data->nr_parts) {
                printk(KERN_NOTICE "Using physmap partition information\n");
-               add_mtd_partitions(info->mtd, physmap_data->parts,
-                                               physmap_data->nr_parts);
+               add_mtd_partitions(info->cmtd, physmap_data->parts,
+                                  physmap_data->nr_parts);
                return 0;
        }
 #endif
 
-       add_mtd_device(info->mtd);
+       add_mtd_device(info->cmtd);
        return 0;
 
 err_out:
@@ -162,9 +200,11 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state
 {
        struct physmap_flash_info *info = platform_get_drvdata(dev);
        int ret = 0;
+       int i;
 
        if (info)
-               ret = info->mtd->suspend(info->mtd);
+               for (i = 0; i < MAX_RESOURCES; i++)
+                       ret |= info->mtd[i]->suspend(info->mtd[i]);
 
        return ret;
 }
@@ -172,27 +212,35 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state
 static int physmap_flash_resume(struct platform_device *dev)
 {
        struct physmap_flash_info *info = platform_get_drvdata(dev);
+       int i;
+
        if (info)
-               info->mtd->resume(info->mtd);
+               for (i = 0; i < MAX_RESOURCES; i++)
+                       info->mtd[i]->resume(info->mtd[i]);
        return 0;
 }
 
 static void physmap_flash_shutdown(struct platform_device *dev)
 {
        struct physmap_flash_info *info = platform_get_drvdata(dev);
-       if (info && info->mtd->suspend(info->mtd) == 0)
-               info->mtd->resume(info->mtd);
+       int i;
+
+       for (i = 0; i < MAX_RESOURCES; i++)
+               if (info && info->mtd[i]->suspend(info->mtd[i]) == 0)
+                       info->mtd[i]->resume(info->mtd[i]);
 }
+#else
+#define physmap_flash_suspend NULL
+#define physmap_flash_resume NULL
+#define physmap_flash_shutdown NULL
 #endif
 
 static struct platform_driver physmap_flash_driver = {
        .probe          = physmap_flash_probe,
        .remove         = physmap_flash_remove,
-#ifdef CONFIG_PM
        .suspend        = physmap_flash_suspend,
        .resume         = physmap_flash_resume,
        .shutdown       = physmap_flash_shutdown,
-#endif
        .driver         = {
                .name   = "physmap-flash",
        },
index aeed9ea79714ab56454840ee34d6eb5395e60f12..49acd41718934f2a671d887c94e6603b596f32f7 100644 (file)
@@ -80,64 +80,6 @@ static int parse_obsolete_partitions(struct of_device *dev,
 
        return nr_parts;
 }
-
-static int __devinit parse_partitions(struct of_flash *info,
-                                     struct of_device *dev)
-{
-       const char *partname;
-       static const char *part_probe_types[]
-               = { "cmdlinepart", "RedBoot", NULL };
-       struct device_node *dp = dev->node, *pp;
-       int nr_parts, i;
-
-       /* First look for RedBoot table or partitions on the command
-        * line, these take precedence over device tree information */
-       nr_parts = parse_mtd_partitions(info->mtd, part_probe_types,
-                                       &info->parts, 0);
-       if (nr_parts > 0) {
-               add_mtd_partitions(info->mtd, info->parts, nr_parts);
-               return 0;
-       }
-
-       /* First count the subnodes */
-       nr_parts = 0;
-       for (pp = dp->child; pp; pp = pp->sibling)
-               nr_parts++;
-
-       if (nr_parts == 0)
-               return parse_obsolete_partitions(dev, info, dp);
-
-       info->parts = kzalloc(nr_parts * sizeof(*info->parts),
-                             GFP_KERNEL);
-       if (!info->parts)
-               return -ENOMEM;
-
-       for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) {
-               const u32 *reg;
-               int len;
-
-               reg = of_get_property(pp, "reg", &len);
-               if (!reg || (len != 2*sizeof(u32))) {
-                       dev_err(&dev->dev, "Invalid 'reg' on %s\n",
-                               dp->full_name);
-                       kfree(info->parts);
-                       info->parts = NULL;
-                       return -EINVAL;
-               }
-               info->parts[i].offset = reg[0];
-               info->parts[i].size = reg[1];
-
-               partname = of_get_property(pp, "label", &len);
-               if (!partname)
-                       partname = of_get_property(pp, "name", &len);
-               info->parts[i].name = (char *)partname;
-
-               if (of_get_property(pp, "read-only", &len))
-                       info->parts[i].mask_flags = MTD_WRITEABLE;
-       }
-
-       return nr_parts;
-}
 #else /* MTD_PARTITIONS */
 #define        OF_FLASH_PARTS(info)            (0)
 #define parse_partitions(info, dev)    (0)
@@ -212,6 +154,10 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
 static int __devinit of_flash_probe(struct of_device *dev,
                                    const struct of_device_id *match)
 {
+#ifdef CONFIG_MTD_PARTITIONS
+       static const char *part_probe_types[]
+               = { "cmdlinepart", "RedBoot", NULL };
+#endif
        struct device_node *dp = dev->node;
        struct resource res;
        struct of_flash *info;
@@ -274,13 +220,33 @@ static int __devinit of_flash_probe(struct of_device *dev,
        }
        info->mtd->owner = THIS_MODULE;
 
-       err = parse_partitions(info, dev);
+#ifdef CONFIG_MTD_PARTITIONS
+       /* First look for RedBoot table or partitions on the command
+        * line, these take precedence over device tree information */
+       err = parse_mtd_partitions(info->mtd, part_probe_types,
+                                  &info->parts, 0);
        if (err < 0)
-               goto err_out;
+               return err;
+
+#ifdef CONFIG_MTD_OF_PARTS
+       if (err == 0) {
+               err = of_mtd_parse_partitions(&dev->dev, info->mtd,
+                                             dp, &info->parts);
+               if (err < 0)
+                       return err;
+       }
+#endif
+
+       if (err == 0) {
+               err = parse_obsolete_partitions(dev, info, dp);
+               if (err < 0)
+                       return err;
+       }
 
        if (err > 0)
-               add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
+               add_mtd_partitions(info->mtd, info->parts, err);
        else
+#endif
                add_mtd_device(info->mtd);
 
        return 0;
diff --git a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c
deleted file mode 100644 (file)
index d7e16c2..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- *     pnc2000.c - mapper for Photron PNC-2000 board.
- *
- * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
- *
- * This code is GPL
- *
- * $Id: pnc2000.c,v 1.18 2005/11/07 11:14:28 gleixner Exp $
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-
-#define WINDOW_ADDR 0xbf000000
-#define WINDOW_SIZE 0x00400000
-
-/*
- * MAP DRIVER STUFF
- */
-
-
-static struct map_info pnc_map = {
-       .name = "PNC-2000",
-       .size = WINDOW_SIZE,
-       .bankwidth = 4,
-       .phys = 0xFFFFFFFF,
-       .virt = (void __iomem *)WINDOW_ADDR,
-};
-
-
-/*
- * MTD 'PARTITIONING' STUFF
- */
-static struct mtd_partition pnc_partitions[3] = {
-       {
-               .name = "PNC-2000 boot firmware",
-               .size = 0x20000,
-               .offset = 0
-       },
-       {
-               .name = "PNC-2000 kernel",
-               .size = 0x1a0000,
-               .offset = 0x20000
-       },
-       {
-               .name = "PNC-2000 filesystem",
-               .size = 0x240000,
-               .offset = 0x1c0000
-       }
-};
-
-/*
- * This is the master MTD device for which all the others are just
- * auto-relocating aliases.
- */
-static struct mtd_info *mymtd;
-
-static int __init init_pnc2000(void)
-{
-       printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-
-       simple_map_init(&pnc_map);
-
-       mymtd = do_map_probe("cfi_probe", &pnc_map);
-       if (mymtd) {
-               mymtd->owner = THIS_MODULE;
-               return add_mtd_partitions(mymtd, pnc_partitions, 3);
-       }
-
-       return -ENXIO;
-}
-
-static void __exit cleanup_pnc2000(void)
-{
-       if (mymtd) {
-               del_mtd_partitions(mymtd);
-               map_destroy(mymtd);
-       }
-}
-
-module_init(init_pnc2000);
-module_exit(cleanup_pnc2000);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp>");
-MODULE_DESCRIPTION("MTD map driver for Photron PNC-2000 board");
index dcfb85840d1e4c5d5fd355dc783b7f55aef75464..0fc5584324e3d38488dd62627867787c2201e5d1 100644 (file)
@@ -79,7 +79,7 @@ scb2_fixup_mtd(struct mtd_info *mtd)
        struct cfi_private *cfi = map->fldrv_priv;
 
        /* barf if this doesn't look right */
-       if (cfi->cfiq->InterfaceDesc != 1) {
+       if (cfi->cfiq->InterfaceDesc != CFI_INTERFACE_X16_ASYNC) {
                printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n",
                    cfi->cfiq->InterfaceDesc);
                return -1;
index 74d9d30edabdc49c04f42b435b53e851f159c3c5..839eed8430a2c77aaf1643937de83ae99501fe6b 100644 (file)
@@ -248,9 +248,9 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
                return -EBUSY;
        }
 
-       mutex_init(&new->lock);
        list_add_tail(&new->list, &tr->devs);
  added:
+       mutex_init(&new->lock);
        if (!tr->writesect)
                new->readonly = 1;
 
index a0cee86464cae51646b148939d49b6c61b8725a1..5d3ac512ce169f1f4efc8de2cde7ae6ca21c6148 100644 (file)
@@ -481,6 +481,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
        {
                struct mtd_oob_buf buf;
                struct mtd_oob_ops ops;
+               uint32_t retlen;
 
                if(!(file->f_mode & 2))
                        return -EPERM;
@@ -520,8 +521,11 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                buf.start &= ~(mtd->oobsize - 1);
                ret = mtd->write_oob(mtd, buf.start, &ops);
 
-               if (copy_to_user(argp + sizeof(uint32_t), &ops.oobretlen,
-                                sizeof(uint32_t)))
+               if (ops.oobretlen > 0xFFFFFFFFU)
+                       ret = -EOVERFLOW;
+               retlen = ops.oobretlen;
+               if (copy_to_user(&((struct mtd_oob_buf *)argp)->length,
+                                &retlen, sizeof(buf.length)))
                        ret = -EFAULT;
 
                kfree(ops.oobbuf);
index 6c2645e2837191e57d539222c92d68b3debac806..f7e7890e5bc6889f1ce0aa9fdc18c7be6cf42e6a 100644 (file)
@@ -61,7 +61,7 @@ int add_mtd_device(struct mtd_info *mtd)
 
                        /* Some chips always power up locked. Unlock them now */
                        if ((mtd->flags & MTD_WRITEABLE)
-                           && (mtd->flags & MTD_STUPID_LOCK) && mtd->unlock) {
+                           && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {
                                if (mtd->unlock(mtd, 0, mtd->size))
                                        printk(KERN_WARNING
                                               "%s: unlock failed, "
index f8af627f0b98e68d2392039c2f4f918a3db842b5..d3cf05012b46a0a9df82888cb39ccd1bfd07f642 100644 (file)
 #include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
 
 #define OOPS_PAGE_SIZE 4096
 
-static struct mtdoops_context {
+struct mtdoops_context {
        int mtd_index;
-       struct work_struct work;
+       struct work_struct work_erase;
+       struct work_struct work_write;
        struct mtd_info *mtd;
        int oops_pages;
        int nextpage;
        int nextcount;
 
        void *oops_buf;
+
+       /* writecount and disabling ready are spin lock protected */
+       spinlock_t writecount_lock;
        int ready;
        int writecount;
 } oops_cxt;
@@ -62,10 +69,7 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
        erase.mtd = mtd;
        erase.callback = mtdoops_erase_callback;
        erase.addr = offset;
-       if (mtd->erasesize < OOPS_PAGE_SIZE)
-               erase.len = OOPS_PAGE_SIZE;
-       else
-               erase.len = mtd->erasesize;
+       erase.len = mtd->erasesize;
        erase.priv = (u_long)&wait_q;
 
        set_current_state(TASK_INTERRUPTIBLE);
@@ -87,7 +91,7 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
        return 0;
 }
 
-static int mtdoops_inc_counter(struct mtdoops_context *cxt)
+static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 {
        struct mtd_info *mtd = cxt->mtd;
        size_t retlen;
@@ -103,25 +107,30 @@ static int mtdoops_inc_counter(struct mtdoops_context *cxt)
 
        ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4,
                        &retlen, (u_char *) &count);
-       if ((retlen != 4) || (ret < 0)) {
+       if ((retlen != 4) || ((ret < 0) && (ret != -EUCLEAN))) {
                printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
                                ", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE,
                                retlen, ret);
-               return 1;
+               schedule_work(&cxt->work_erase);
+               return;
        }
 
        /* See if we need to erase the next block */
-       if (count != 0xffffffff)
-               return 1;
+       if (count != 0xffffffff) {
+               schedule_work(&cxt->work_erase);
+               return;
+       }
 
        printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n",
                        cxt->nextpage, cxt->nextcount);
        cxt->ready = 1;
-       return 0;
 }
 
-static void mtdoops_prepare(struct mtdoops_context *cxt)
+/* Scheduled work - when we can't proceed without erasing a block */
+static void mtdoops_workfunc_erase(struct work_struct *work)
 {
+       struct mtdoops_context *cxt =
+                       container_of(work, struct mtdoops_context, work_erase);
        struct mtd_info *mtd = cxt->mtd;
        int i = 0, j, ret, mod;
 
@@ -136,8 +145,14 @@ static void mtdoops_prepare(struct mtdoops_context *cxt)
                        cxt->nextpage = 0;
        }
 
-       while (mtd->block_isbad &&
-                       mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE)) {
+       while (mtd->block_isbad) {
+               ret = mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+               if (!ret)
+                       break;
+               if (ret < 0) {
+                       printk(KERN_ERR "mtdoops: block_isbad failed, aborting.\n");
+                       return;
+               }
 badblock:
                printk(KERN_WARNING "mtdoops: Bad block at %08x\n",
                                cxt->nextpage * OOPS_PAGE_SIZE);
@@ -154,34 +169,72 @@ badblock:
        for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
                ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
 
-       if (ret < 0) {
-               if (mtd->block_markbad)
-                       mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
-               goto badblock;
+       if (ret >= 0) {
+               printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount);
+               cxt->ready = 1;
+               return;
        }
 
-       printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount);
+       if (mtd->block_markbad && (ret == -EIO)) {
+               ret = mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+               if (ret < 0) {
+                       printk(KERN_ERR "mtdoops: block_markbad failed, aborting.\n");
+                       return;
+               }
+       }
+       goto badblock;
+}
 
-       cxt->ready = 1;
+static void mtdoops_write(struct mtdoops_context *cxt, int panic)
+{
+       struct mtd_info *mtd = cxt->mtd;
+       size_t retlen;
+       int ret;
+
+       if (cxt->writecount < OOPS_PAGE_SIZE)
+               memset(cxt->oops_buf + cxt->writecount, 0xff,
+                                       OOPS_PAGE_SIZE - cxt->writecount);
+
+       if (panic)
+               ret = mtd->panic_write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
+                                       OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+       else
+               ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
+                                       OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+
+       cxt->writecount = 0;
+
+       if ((retlen != OOPS_PAGE_SIZE) || (ret < 0))
+               printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n",
+                       cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
+
+       mtdoops_inc_counter(cxt);
 }
 
-static void mtdoops_workfunc(struct work_struct *work)
+
+static void mtdoops_workfunc_write(struct work_struct *work)
 {
        struct mtdoops_context *cxt =
-                       container_of(work, struct mtdoops_context, work);
+                       container_of(work, struct mtdoops_context, work_write);
 
-       mtdoops_prepare(cxt);
-}
+       mtdoops_write(cxt, 0);
+}                                      
 
-static int find_next_position(struct mtdoops_context *cxt)
+static void find_next_position(struct mtdoops_context *cxt)
 {
        struct mtd_info *mtd = cxt->mtd;
-       int page, maxpos = 0;
+       int ret, page, maxpos = 0;
        u32 count, maxcount = 0xffffffff;
        size_t retlen;
 
        for (page = 0; page < cxt->oops_pages; page++) {
-               mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
+               ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
+               if ((retlen != 4) || ((ret < 0) && (ret != -EUCLEAN))) {
+                       printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
+                               ", err %d.\n", page * OOPS_PAGE_SIZE, retlen, ret);
+                       continue;
+               }
+
                if (count == 0xffffffff)
                        continue;
                if (maxcount == 0xffffffff) {
@@ -205,20 +258,19 @@ static int find_next_position(struct mtdoops_context *cxt)
                cxt->ready = 1;
                printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n",
                                cxt->nextpage, cxt->nextcount);
-               return 0;
+               return;
        }
 
        cxt->nextpage = maxpos;
        cxt->nextcount = maxcount;
 
-       return mtdoops_inc_counter(cxt);
+       mtdoops_inc_counter(cxt);
 }
 
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
        struct mtdoops_context *cxt = &oops_cxt;
-       int ret;
 
        if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
                return;
@@ -229,14 +281,18 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
                return;
        }
 
+       if (mtd->erasesize < OOPS_PAGE_SIZE) {
+               printk(KERN_ERR "Eraseblock size of MTD partition %d too small\n",
+                               mtd->index);
+               return;
+       }
+
        cxt->mtd = mtd;
        cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE;
 
-       ret = find_next_position(cxt);
-       if (ret == 1)
-               mtdoops_prepare(cxt);
+       find_next_position(cxt);
 
-       printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index);
+       printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index);
 }
 
 static void mtdoops_notify_remove(struct mtd_info *mtd)
@@ -254,31 +310,28 @@ static void mtdoops_console_sync(void)
 {
        struct mtdoops_context *cxt = &oops_cxt;
        struct mtd_info *mtd = cxt->mtd;
-       size_t retlen;
-       int ret;
+       unsigned long flags;
 
-       if (!cxt->ready || !mtd)
+       if (!cxt->ready || !mtd || cxt->writecount == 0)
                return;
 
-       if (cxt->writecount == 0)
+       /* 
+        *  Once ready is 0 and we've held the lock no further writes to the 
+        *  buffer will happen
+        */
+       spin_lock_irqsave(&cxt->writecount_lock, flags);
+       if (!cxt->ready) {
+               spin_unlock_irqrestore(&cxt->writecount_lock, flags);
                return;
-
-       if (cxt->writecount < OOPS_PAGE_SIZE)
-               memset(cxt->oops_buf + cxt->writecount, 0xff,
-                                       OOPS_PAGE_SIZE - cxt->writecount);
-
-       ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
-                                       OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+       }
        cxt->ready = 0;
-       cxt->writecount = 0;
-
-       if ((retlen != OOPS_PAGE_SIZE) || (ret < 0))
-               printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n",
-                       cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
+       spin_unlock_irqrestore(&cxt->writecount_lock, flags);
 
-       ret = mtdoops_inc_counter(cxt);
-       if (ret == 1)
-               schedule_work(&cxt->work);
+       if (mtd->panic_write && in_interrupt())
+               /* Interrupt context, we're going to panic so try and log */
+               mtdoops_write(cxt, 1);
+       else
+               schedule_work(&cxt->work_write);
 }
 
 static void
@@ -286,7 +339,7 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct mtdoops_context *cxt = co->data;
        struct mtd_info *mtd = cxt->mtd;
-       int i;
+       unsigned long flags;
 
        if (!oops_in_progress) {
                mtdoops_console_sync();
@@ -296,6 +349,13 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
        if (!cxt->ready || !mtd)
                return;
 
+       /* Locking on writecount ensures sequential writes to the buffer */
+       spin_lock_irqsave(&cxt->writecount_lock, flags);
+
+       /* Check ready status didn't change whilst waiting for the lock */
+       if (!cxt->ready)
+               return;
+
        if (cxt->writecount == 0) {
                u32 *stamp = cxt->oops_buf;
                *stamp = cxt->nextcount;
@@ -305,10 +365,13 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
        if ((count + cxt->writecount) > OOPS_PAGE_SIZE)
                count = OOPS_PAGE_SIZE - cxt->writecount;
 
-       for (i = 0; i < count; i++, s++)
-               *((char *)(cxt->oops_buf) + cxt->writecount + i) = *s;
+       memcpy(cxt->oops_buf + cxt->writecount, s, count);
+       cxt->writecount += count;
 
-       cxt->writecount = cxt->writecount + count;
+       spin_unlock_irqrestore(&cxt->writecount_lock, flags);
+
+       if (cxt->writecount == OOPS_PAGE_SIZE)
+               mtdoops_console_sync();
 }
 
 static int __init mtdoops_console_setup(struct console *co, char *options)
@@ -334,7 +397,6 @@ static struct console mtdoops_console = {
        .write          = mtdoops_console_write,
        .setup          = mtdoops_console_setup,
        .unblank        = mtdoops_console_sync,
-       .flags          = CON_PRINTBUFFER,
        .index          = -1,
        .data           = &oops_cxt,
 };
@@ -347,11 +409,12 @@ static int __init mtdoops_console_init(void)
        cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE);
 
        if (!cxt->oops_buf) {
-               printk(KERN_ERR "Failed to allocate oops buffer workspace\n");
+               printk(KERN_ERR "Failed to allocate mtdoops buffer workspace\n");
                return -ENOMEM;
        }
 
-       INIT_WORK(&cxt->work, mtdoops_workfunc);
+       INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase);
+       INIT_WORK(&cxt->work_write, mtdoops_workfunc_write);
 
        register_console(&mtdoops_console);
        register_mtd_user(&mtdoops_notifier);
index 6174a97d790274f5aa1245dc53171c324482ebb9..c66902df3171aef08e1066fde0157992f456ffdc 100644 (file)
@@ -151,6 +151,20 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
                                    len, retlen, buf);
 }
 
+static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len,
+                       size_t *retlen, const u_char *buf)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
+       if (to >= mtd->size)
+               len = 0;
+       else if (to + len > mtd->size)
+               len = mtd->size - to;
+       return part->master->panic_write (part->master, to + part->offset,
+                                   len, retlen, buf);
+}
+
 static int part_write_oob(struct mtd_info *mtd, loff_t to,
                         struct mtd_oob_ops *ops)
 {
@@ -352,6 +366,9 @@ int add_mtd_partitions(struct mtd_info *master,
                slave->mtd.read = part_read;
                slave->mtd.write = part_write;
 
+               if (master->panic_write)
+                       slave->mtd.panic_write = part_panic_write;
+
                if(master->point && master->unpoint){
                        slave->mtd.point = part_point;
                        slave->mtd.unpoint = part_unpoint;
index 246d4512f64bfd8670a5731809d1280cd2cbfcaa..4a3c6759492b95b4a18150c0f63003f9e2ee211c 100644 (file)
@@ -93,7 +93,7 @@ config MTD_NAND_AU1550
 
 config MTD_NAND_BF5XX
        tristate "Blackfin on-chip NAND Flash Controller driver"
-       depends on BF54x && MTD_NAND
+       depends on (BF54x || BF52x) && MTD_NAND
        help
          This enables the Blackfin on-chip NAND flash controller
 
@@ -283,6 +283,12 @@ config MTD_NAND_CM_X270
        tristate "Support for NAND Flash on CM-X270 modules"
        depends on MTD_NAND && MACH_ARMCORE
 
+config MTD_NAND_PASEMI
+       tristate "NAND support for PA Semi PWRficient"
+       depends on MTD_NAND && PPC_PASEMI
+       help
+         Enables support for NAND Flash interface on PA Semi PWRficient
+         based boards
 
 config MTD_NAND_NANDSIM
        tristate "Support for NAND Flash Simulator"
@@ -306,4 +312,22 @@ config MTD_ALAUDA
          These two (and possibly other) Alauda-based cardreaders for
          SmartMedia and xD allow raw flash access.
 
+config MTD_NAND_ORION
+       tristate "NAND Flash support for Marvell Orion SoC"
+       depends on ARCH_ORION && MTD_NAND
+       help
+         This enables the NAND flash controller on Orion machines.
+
+         No board specific support is done by this driver, each board
+         must advertise a platform_device for the driver to attach.
+
+config MTD_NAND_FSL_ELBC
+       tristate "NAND support for Freescale eLBC controllers"
+       depends on MTD_NAND && PPC_OF
+       help
+         Various Freescale chips, including the 8313, include a NAND Flash
+         Controller Module with built-in hardware ECC capabilities.
+         Enabling this option will enable you to use this to control
+         external NAND devices.
+
 endif # MTD_NAND
index 3ad6c0165da3ab77ef17c80196b313ce29305cc4..80d575eeee96663ba0ea51a7256949e18179a271 100644 (file)
@@ -29,5 +29,8 @@ obj-$(CONFIG_MTD_NAND_CM_X270)                += cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)   += excite_nandflash.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)                += plat_nand.o
 obj-$(CONFIG_MTD_ALAUDA)               += alauda.o
+obj-$(CONFIG_MTD_NAND_PASEMI)          += pasemi_nand.o
+obj-$(CONFIG_MTD_NAND_ORION)           += orion_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_ELBC)                += fsl_elbc_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
index b2a5672df6e0a15a2c1b2f2183087883c1a9f35e..c9fb2acf4056b3baab4ccb1ab1e980b2af08d026 100644 (file)
@@ -156,14 +156,14 @@ static int __init at91_nand_probe(struct platform_device *pdev)
        }
 
 #ifdef CONFIG_MTD_PARTITIONS
-       if (host->board->partition_info)
-               partitions = host->board->partition_info(mtd->size, &num_partitions);
 #ifdef CONFIG_MTD_CMDLINE_PARTS
-       else {
-               mtd->name = "at91_nand";
-               num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
-       }
+       mtd->name = "at91_nand";
+       num_partitions = parse_mtd_partitions(mtd, part_probes,
+                                             &partitions, 0);
 #endif
+       if (num_partitions <= 0 && host->board->partition_info)
+               partitions = host->board->partition_info(mtd->size,
+                                                        &num_partitions);
 
        if ((!partitions) || (num_partitions == 0)) {
                printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
index a52f3a737c39a606e0832b3db47f19effa274a83..747042ab094a6b101e558a4f379ff9b2848a81c1 100644 (file)
@@ -74,7 +74,22 @@ static int hardware_ecc = 1;
 static int hardware_ecc;
 #endif
 
-static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0};
+static unsigned short bfin_nfc_pin_req[] =
+       {P_NAND_CE,
+        P_NAND_RB,
+        P_NAND_D0,
+        P_NAND_D1,
+        P_NAND_D2,
+        P_NAND_D3,
+        P_NAND_D4,
+        P_NAND_D5,
+        P_NAND_D6,
+        P_NAND_D7,
+        P_NAND_WE,
+        P_NAND_RE,
+        P_NAND_CLE,
+        P_NAND_ALE,
+        0};
 
 /*
  * Data structures for bf5xx nand flash controller driver
@@ -278,7 +293,6 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
        u16 ecc0, ecc1;
        u32 code[2];
        u8 *p;
-       int bytes = 3, i;
 
        /* first 4 bytes ECC code for 256 page size */
        ecc0 = bfin_read_NFC_ECC0();
@@ -288,19 +302,24 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
 
        dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
 
+       /* first 3 bytes in ecc_code for 256 page size */
+       p = (u8 *) code;
+       memcpy(ecc_code, p, 3);
+
        /* second 4 bytes ECC code for 512 page size */
        if (page_size == 512) {
                ecc0 = bfin_read_NFC_ECC2();
                ecc1 = bfin_read_NFC_ECC3();
                code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
-               bytes = 6;
+
+               /* second 3 bytes in ecc_code for second 256
+                * bytes of 512 page size
+                */
+               p = (u8 *) (code + 1);
+               memcpy((ecc_code + 3), p, 3);
                dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
        }
 
-       p = (u8 *)code;
-       for (i = 0; i < bytes; i++)
-               ecc_code[i] = p[i];
-
        return 0;
 }
 
@@ -507,12 +526,13 @@ static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
 
        init_completion(&info->dma_completion);
 
+#ifdef CONFIG_BF54x
        /* Setup DMAC1 channel mux for NFC which shared with SDH */
        val = bfin_read_DMAC1_PERIMUX();
        val &= 0xFFFE;
        bfin_write_DMAC1_PERIMUX(val);
        SSYNC();
-
+#endif
        /* Request NFC DMA channel */
        ret = request_dma(CH_NFC, "BF5XX NFC driver");
        if (ret < 0) {
@@ -744,9 +764,6 @@ static int bf5xx_nand_resume(struct platform_device *dev)
 {
        struct bf5xx_nand_info *info = platform_get_drvdata(dev);
 
-       if (info)
-               bf5xx_nand_hw_init(info);
-
        return 0;
 }
 
index 1e811715211a56f8417bd1c8f107566b6a06d2b4..da6ceaa80ba137c1c4114a199d59efb09bcf08ed 100644 (file)
@@ -11,6 +11,7 @@
 #undef DEBUG
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
 #include <linux/rslib.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -52,6 +53,7 @@
 
 struct cafe_priv {
        struct nand_chip nand;
+       struct mtd_partition *parts;
        struct pci_dev *pdev;
        void __iomem *mmio;
        struct rs_control *rs;
@@ -84,6 +86,10 @@ static unsigned int numtimings;
 static int timing[3];
 module_param_array(timing, int, &numtimings, 0644);
 
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "RedBoot", NULL };
+#endif
+
 /* Hrm. Why isn't this already conditional on something in the struct device? */
 #define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
 
@@ -620,7 +626,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
 {
        struct mtd_info *mtd;
        struct cafe_priv *cafe;
+       struct mtd_partition *parts;
        uint32_t ctrl;
+       int nr_parts;
        int err = 0;
 
        /* Very old versions shared the same PCI ident for all three
@@ -787,7 +795,18 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
                goto out_irq;
 
        pci_set_drvdata(pdev, mtd);
+
+       /* We register the whole device first, separate from the partitions */
        add_mtd_device(mtd);
+
+#ifdef CONFIG_MTD_PARTITIONS
+       nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
+       if (nr_parts > 0) {
+               cafe->parts = parts;
+               dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts);
+               add_mtd_partitions(mtd, parts, nr_parts);
+       }
+#endif
        goto out;
 
  out_irq:
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
new file mode 100644 (file)
index 0000000..b025dfe
--- /dev/null
@@ -0,0 +1,1244 @@
+/* Freescale Enhanced Local Bus Controller NAND driver
+ *
+ * Copyright (c) 2006-2007 Freescale Semiconductor
+ *
+ * Authors: Nick Spence <nick.spence@freescale.com>,
+ *          Scott Wood <scottwood@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+
+#define MAX_BANKS 8
+#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
+#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
+
+struct elbc_bank {
+       __be32 br;             /**< Base Register  */
+#define BR_BA           0xFFFF8000
+#define BR_BA_SHIFT             15
+#define BR_PS           0x00001800
+#define BR_PS_SHIFT             11
+#define BR_PS_8         0x00000800  /* Port Size 8 bit */
+#define BR_PS_16        0x00001000  /* Port Size 16 bit */
+#define BR_PS_32        0x00001800  /* Port Size 32 bit */
+#define BR_DECC         0x00000600
+#define BR_DECC_SHIFT            9
+#define BR_DECC_OFF     0x00000000  /* HW ECC checking and generation off */
+#define BR_DECC_CHK     0x00000200  /* HW ECC checking on, generation off */
+#define BR_DECC_CHK_GEN 0x00000400  /* HW ECC checking and generation on */
+#define BR_WP           0x00000100
+#define BR_WP_SHIFT              8
+#define BR_MSEL         0x000000E0
+#define BR_MSEL_SHIFT            5
+#define BR_MS_GPCM      0x00000000  /* GPCM */
+#define BR_MS_FCM       0x00000020  /* FCM */
+#define BR_MS_SDRAM     0x00000060  /* SDRAM */
+#define BR_MS_UPMA      0x00000080  /* UPMA */
+#define BR_MS_UPMB      0x000000A0  /* UPMB */
+#define BR_MS_UPMC      0x000000C0  /* UPMC */
+#define BR_V            0x00000001
+#define BR_V_SHIFT               0
+#define BR_RES          ~(BR_BA|BR_PS|BR_DECC|BR_WP|BR_MSEL|BR_V)
+
+       __be32 or;             /**< Base Register  */
+#define OR0 0x5004
+#define OR1 0x500C
+#define OR2 0x5014
+#define OR3 0x501C
+#define OR4 0x5024
+#define OR5 0x502C
+#define OR6 0x5034
+#define OR7 0x503C
+
+#define OR_FCM_AM               0xFFFF8000
+#define OR_FCM_AM_SHIFT                 15
+#define OR_FCM_BCTLD            0x00001000
+#define OR_FCM_BCTLD_SHIFT              12
+#define OR_FCM_PGS              0x00000400
+#define OR_FCM_PGS_SHIFT                10
+#define OR_FCM_CSCT             0x00000200
+#define OR_FCM_CSCT_SHIFT                9
+#define OR_FCM_CST              0x00000100
+#define OR_FCM_CST_SHIFT                 8
+#define OR_FCM_CHT              0x00000080
+#define OR_FCM_CHT_SHIFT                 7
+#define OR_FCM_SCY              0x00000070
+#define OR_FCM_SCY_SHIFT                 4
+#define OR_FCM_SCY_1            0x00000010
+#define OR_FCM_SCY_2            0x00000020
+#define OR_FCM_SCY_3            0x00000030
+#define OR_FCM_SCY_4            0x00000040
+#define OR_FCM_SCY_5            0x00000050
+#define OR_FCM_SCY_6            0x00000060
+#define OR_FCM_SCY_7            0x00000070
+#define OR_FCM_RST              0x00000008
+#define OR_FCM_RST_SHIFT                 3
+#define OR_FCM_TRLX             0x00000004
+#define OR_FCM_TRLX_SHIFT                2
+#define OR_FCM_EHTR             0x00000002
+#define OR_FCM_EHTR_SHIFT                1
+};
+
+struct elbc_regs {
+       struct elbc_bank bank[8];
+       u8 res0[0x28];
+       __be32 mar;             /**< UPM Address Register */
+       u8 res1[0x4];
+       __be32 mamr;            /**< UPMA Mode Register */
+       __be32 mbmr;            /**< UPMB Mode Register */
+       __be32 mcmr;            /**< UPMC Mode Register */
+       u8 res2[0x8];
+       __be32 mrtpr;           /**< Memory Refresh Timer Prescaler Register */
+       __be32 mdr;             /**< UPM Data Register */
+       u8 res3[0x4];
+       __be32 lsor;            /**< Special Operation Initiation Register */
+       __be32 lsdmr;           /**< SDRAM Mode Register */
+       u8 res4[0x8];
+       __be32 lurt;            /**< UPM Refresh Timer */
+       __be32 lsrt;            /**< SDRAM Refresh Timer */
+       u8 res5[0x8];
+       __be32 ltesr;           /**< Transfer Error Status Register */
+#define LTESR_BM   0x80000000
+#define LTESR_FCT  0x40000000
+#define LTESR_PAR  0x20000000
+#define LTESR_WP   0x04000000
+#define LTESR_ATMW 0x00800000
+#define LTESR_ATMR 0x00400000
+#define LTESR_CS   0x00080000
+#define LTESR_CC   0x00000001
+#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
+       __be32 ltedr;           /**< Transfer Error Disable Register */
+       __be32 lteir;           /**< Transfer Error Interrupt Register */
+       __be32 lteatr;          /**< Transfer Error Attributes Register */
+       __be32 ltear;           /**< Transfer Error Address Register */
+       u8 res6[0xC];
+       __be32 lbcr;            /**< Configuration Register */
+#define LBCR_LDIS  0x80000000
+#define LBCR_LDIS_SHIFT    31
+#define LBCR_BCTLC 0x00C00000
+#define LBCR_BCTLC_SHIFT   22
+#define LBCR_AHD   0x00200000
+#define LBCR_LPBSE 0x00020000
+#define LBCR_LPBSE_SHIFT   17
+#define LBCR_EPAR  0x00010000
+#define LBCR_EPAR_SHIFT    16
+#define LBCR_BMT   0x0000FF00
+#define LBCR_BMT_SHIFT      8
+#define LBCR_INIT  0x00040000
+       __be32 lcrr;            /**< Clock Ratio Register */
+#define LCRR_DBYP    0x80000000
+#define LCRR_DBYP_SHIFT      31
+#define LCRR_BUFCMDC 0x30000000
+#define LCRR_BUFCMDC_SHIFT   28
+#define LCRR_ECL     0x03000000
+#define LCRR_ECL_SHIFT       24
+#define LCRR_EADC    0x00030000
+#define LCRR_EADC_SHIFT      16
+#define LCRR_CLKDIV  0x0000000F
+#define LCRR_CLKDIV_SHIFT     0
+       u8 res7[0x8];
+       __be32 fmr;             /**< Flash Mode Register */
+#define FMR_CWTO     0x0000F000
+#define FMR_CWTO_SHIFT       12
+#define FMR_BOOT     0x00000800
+#define FMR_ECCM     0x00000100
+#define FMR_AL       0x00000030
+#define FMR_AL_SHIFT          4
+#define FMR_OP       0x00000003
+#define FMR_OP_SHIFT          0
+       __be32 fir;             /**< Flash Instruction Register */
+#define FIR_OP0      0xF0000000
+#define FIR_OP0_SHIFT        28
+#define FIR_OP1      0x0F000000
+#define FIR_OP1_SHIFT        24
+#define FIR_OP2      0x00F00000
+#define FIR_OP2_SHIFT        20
+#define FIR_OP3      0x000F0000
+#define FIR_OP3_SHIFT        16
+#define FIR_OP4      0x0000F000
+#define FIR_OP4_SHIFT        12
+#define FIR_OP5      0x00000F00
+#define FIR_OP5_SHIFT         8
+#define FIR_OP6      0x000000F0
+#define FIR_OP6_SHIFT         4
+#define FIR_OP7      0x0000000F
+#define FIR_OP7_SHIFT         0
+#define FIR_OP_NOP   0x0       /* No operation and end of sequence */
+#define FIR_OP_CA    0x1        /* Issue current column address */
+#define FIR_OP_PA    0x2        /* Issue current block+page address */
+#define FIR_OP_UA    0x3        /* Issue user defined address */
+#define FIR_OP_CM0   0x4        /* Issue command from FCR[CMD0] */
+#define FIR_OP_CM1   0x5        /* Issue command from FCR[CMD1] */
+#define FIR_OP_CM2   0x6        /* Issue command from FCR[CMD2] */
+#define FIR_OP_CM3   0x7        /* Issue command from FCR[CMD3] */
+#define FIR_OP_WB    0x8        /* Write FBCR bytes from FCM buffer */
+#define FIR_OP_WS    0x9        /* Write 1 or 2 bytes from MDR[AS] */
+#define FIR_OP_RB    0xA        /* Read FBCR bytes to FCM buffer */
+#define FIR_OP_RS    0xB        /* Read 1 or 2 bytes to MDR[AS] */
+#define FIR_OP_CW0   0xC        /* Wait then issue FCR[CMD0] */
+#define FIR_OP_CW1   0xD        /* Wait then issue FCR[CMD1] */
+#define FIR_OP_RBW   0xE        /* Wait then read FBCR bytes */
+#define FIR_OP_RSW   0xE        /* Wait then read 1 or 2 bytes */
+       __be32 fcr;             /**< Flash Command Register */
+#define FCR_CMD0     0xFF000000
+#define FCR_CMD0_SHIFT       24
+#define FCR_CMD1     0x00FF0000
+#define FCR_CMD1_SHIFT       16
+#define FCR_CMD2     0x0000FF00
+#define FCR_CMD2_SHIFT        8
+#define FCR_CMD3     0x000000FF
+#define FCR_CMD3_SHIFT        0
+       __be32 fbar;            /**< Flash Block Address Register */
+#define FBAR_BLK     0x00FFFFFF
+       __be32 fpar;            /**< Flash Page Address Register */
+#define FPAR_SP_PI   0x00007C00
+#define FPAR_SP_PI_SHIFT     10
+#define FPAR_SP_MS   0x00000200
+#define FPAR_SP_CI   0x000001FF
+#define FPAR_SP_CI_SHIFT      0
+#define FPAR_LP_PI   0x0003F000
+#define FPAR_LP_PI_SHIFT     12
+#define FPAR_LP_MS   0x00000800
+#define FPAR_LP_CI   0x000007FF
+#define FPAR_LP_CI_SHIFT      0
+       __be32 fbcr;            /**< Flash Byte Count Register */
+#define FBCR_BC      0x00000FFF
+       u8 res11[0x8];
+       u8 res8[0xF00];
+};
+
+struct fsl_elbc_ctrl;
+
+/* mtd information per set */
+
+struct fsl_elbc_mtd {
+       struct mtd_info mtd;
+       struct nand_chip chip;
+       struct fsl_elbc_ctrl *ctrl;
+
+       struct device *dev;
+       int bank;               /* Chip select bank number           */
+       u8 __iomem *vbase;      /* Chip select base virtual address  */
+       int page_size;          /* NAND page size (0=512, 1=2048)    */
+       unsigned int fmr;       /* FCM Flash Mode Register value     */
+};
+
+/* overview of the fsl elbc controller */
+
+struct fsl_elbc_ctrl {
+       struct nand_hw_control controller;
+       struct fsl_elbc_mtd *chips[MAX_BANKS];
+
+       /* device info */
+       struct device *dev;
+       struct elbc_regs __iomem *regs;
+       int irq;
+       wait_queue_head_t irq_wait;
+       unsigned int irq_status; /* status read from LTESR by irq handler */
+       u8 __iomem *addr;        /* Address of assigned FCM buffer        */
+       unsigned int page;       /* Last page written to / read from      */
+       unsigned int read_bytes; /* Number of bytes read during command   */
+       unsigned int column;     /* Saved column from SEQIN               */
+       unsigned int index;      /* Pointer to next byte to 'read'        */
+       unsigned int status;     /* status read from LTESR after last op  */
+       unsigned int mdr;        /* UPM/FCM Data Register value           */
+       unsigned int use_mdr;    /* Non zero if the MDR is to be set      */
+       unsigned int oob;        /* Non zero if operating on OOB data     */
+       char *oob_poi;           /* Place to write ECC after read back    */
+};
+
+/* These map to the positions used by the FCM hardware ECC generator */
+
+/* Small Page FLASH with FMR[ECCM] = 0 */
+static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
+       .eccbytes = 3,
+       .eccpos = {6, 7, 8},
+       .oobfree = { {0, 5}, {9, 7} },
+       .oobavail = 12,
+};
+
+/* Small Page FLASH with FMR[ECCM] = 1 */
+static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
+       .eccbytes = 3,
+       .eccpos = {8, 9, 10},
+       .oobfree = { {0, 5}, {6, 2}, {11, 5} },
+       .oobavail = 12,
+};
+
+/* Large Page FLASH with FMR[ECCM] = 0 */
+static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
+       .eccbytes = 12,
+       .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
+       .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} },
+       .oobavail = 48,
+};
+
+/* Large Page FLASH with FMR[ECCM] = 1 */
+static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
+       .eccbytes = 12,
+       .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
+       .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
+       .oobavail = 48,
+};
+
+/*=================================*/
+
+/*
+ * Set up the FCM hardware block and page address fields, and the fcm
+ * structure addr field to point to the correct FCM buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+       int buf_num;
+
+       ctrl->page = page_addr;
+
+       out_be32(&lbc->fbar,
+                page_addr >> (chip->phys_erase_shift - chip->page_shift));
+
+       if (priv->page_size) {
+               out_be32(&lbc->fpar,
+                        ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
+                        (oob ? FPAR_LP_MS : 0) | column);
+               buf_num = (page_addr & 1) << 2;
+       } else {
+               out_be32(&lbc->fpar,
+                        ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
+                        (oob ? FPAR_SP_MS : 0) | column);
+               buf_num = page_addr & 7;
+       }
+
+       ctrl->addr = priv->vbase + buf_num * 1024;
+       ctrl->index = column;
+
+       /* for OOB data point to the second half of the buffer */
+       if (oob)
+               ctrl->index += priv->page_size ? 2048 : 512;
+
+       dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), "
+                           "index %x, pes %d ps %d\n",
+                buf_num, ctrl->addr, priv->vbase, ctrl->index,
+                chip->phys_erase_shift, chip->page_shift);
+}
+
+/*
+ * execute FCM command and wait for it to complete
+ */
+static int fsl_elbc_run_command(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+
+       /* Setup the FMR[OP] to execute without write protection */
+       out_be32(&lbc->fmr, priv->fmr | 3);
+       if (ctrl->use_mdr)
+               out_be32(&lbc->mdr, ctrl->mdr);
+
+       dev_vdbg(ctrl->dev,
+                "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
+                in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
+       dev_vdbg(ctrl->dev,
+                "fsl_elbc_run_command: fbar=%08x fpar=%08x "
+                "fbcr=%08x bank=%d\n",
+                in_be32(&lbc->fbar), in_be32(&lbc->fpar),
+                in_be32(&lbc->fbcr), priv->bank);
+
+       /* execute special operation */
+       out_be32(&lbc->lsor, priv->bank);
+
+       /* wait for FCM complete flag or timeout */
+       ctrl->irq_status = 0;
+       wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
+                          FCM_TIMEOUT_MSECS * HZ/1000);
+       ctrl->status = ctrl->irq_status;
+
+       /* store mdr value in case it was needed */
+       if (ctrl->use_mdr)
+               ctrl->mdr = in_be32(&lbc->mdr);
+
+       ctrl->use_mdr = 0;
+
+       dev_vdbg(ctrl->dev,
+                "fsl_elbc_run_command: stat=%08x mdr=%08x fmr=%08x\n",
+                ctrl->status, ctrl->mdr, in_be32(&lbc->fmr));
+
+       /* returns 0 on success otherwise non-zero) */
+       return ctrl->status == LTESR_CC ? 0 : -EIO;
+}
+
+static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
+{
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+
+       if (priv->page_size) {
+               out_be32(&lbc->fir,
+                        (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+                        (FIR_OP_CA  << FIR_OP1_SHIFT) |
+                        (FIR_OP_PA  << FIR_OP2_SHIFT) |
+                        (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+                        (FIR_OP_RBW << FIR_OP4_SHIFT));
+
+               out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+                                   (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+       } else {
+               out_be32(&lbc->fir,
+                        (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+                        (FIR_OP_CA  << FIR_OP1_SHIFT) |
+                        (FIR_OP_PA  << FIR_OP2_SHIFT) |
+                        (FIR_OP_RBW << FIR_OP3_SHIFT));
+
+               if (oob)
+                       out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
+               else
+                       out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
+       }
+}
+
+/* cmdfunc send commands to the FCM */
+static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+                             int column, int page_addr)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+
+       ctrl->use_mdr = 0;
+
+       /* clear the read buffer */
+       ctrl->read_bytes = 0;
+       if (command != NAND_CMD_PAGEPROG)
+               ctrl->index = 0;
+
+       switch (command) {
+       /* READ0 and READ1 read the entire buffer to use hardware ECC. */
+       case NAND_CMD_READ1:
+               column += 256;
+
+       /* fall-through */
+       case NAND_CMD_READ0:
+               dev_dbg(ctrl->dev,
+                       "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
+                       " 0x%x, column: 0x%x.\n", page_addr, column);
+
+
+               out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
+               set_addr(mtd, 0, page_addr, 0);
+
+               ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+               ctrl->index += column;
+
+               fsl_elbc_do_read(chip, 0);
+               fsl_elbc_run_command(mtd);
+               return;
+
+       /* READOOB reads only the OOB because no ECC is performed. */
+       case NAND_CMD_READOOB:
+               dev_vdbg(ctrl->dev,
+                        "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
+                        " 0x%x, column: 0x%x.\n", page_addr, column);
+
+               out_be32(&lbc->fbcr, mtd->oobsize - column);
+               set_addr(mtd, column, page_addr, 1);
+
+               ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+               fsl_elbc_do_read(chip, 1);
+               fsl_elbc_run_command(mtd);
+               return;
+
+       /* READID must read all 5 possible bytes while CEB is active */
+       case NAND_CMD_READID:
+               dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
+
+               out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+                                   (FIR_OP_UA  << FIR_OP1_SHIFT) |
+                                   (FIR_OP_RBW << FIR_OP2_SHIFT));
+               out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
+               /* 5 bytes for manuf, device and exts */
+               out_be32(&lbc->fbcr, 5);
+               ctrl->read_bytes = 5;
+               ctrl->use_mdr = 1;
+               ctrl->mdr = 0;
+
+               set_addr(mtd, 0, 0, 0);
+               fsl_elbc_run_command(mtd);
+               return;
+
+       /* ERASE1 stores the block and page address */
+       case NAND_CMD_ERASE1:
+               dev_vdbg(ctrl->dev,
+                        "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
+                        "page_addr: 0x%x.\n", page_addr);
+               set_addr(mtd, 0, page_addr, 0);
+               return;
+
+       /* ERASE2 uses the block and page address from ERASE1 */
+       case NAND_CMD_ERASE2:
+               dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
+
+               out_be32(&lbc->fir,
+                        (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+                        (FIR_OP_PA  << FIR_OP1_SHIFT) |
+                        (FIR_OP_CM1 << FIR_OP2_SHIFT));
+
+               out_be32(&lbc->fcr,
+                        (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
+                        (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT));
+
+               out_be32(&lbc->fbcr, 0);
+               ctrl->read_bytes = 0;
+
+               fsl_elbc_run_command(mtd);
+               return;
+
+       /* SEQIN sets up the addr buffer and all registers except the length */
+       case NAND_CMD_SEQIN: {
+               __be32 fcr;
+               dev_vdbg(ctrl->dev,
+                        "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
+                        "page_addr: 0x%x, column: 0x%x.\n",
+                        page_addr, column);
+
+               ctrl->column = column;
+               ctrl->oob = 0;
+
+               fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
+                     (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
+
+               if (priv->page_size) {
+                       out_be32(&lbc->fir,
+                                (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+                                (FIR_OP_CA  << FIR_OP1_SHIFT) |
+                                (FIR_OP_PA  << FIR_OP2_SHIFT) |
+                                (FIR_OP_WB  << FIR_OP3_SHIFT) |
+                                (FIR_OP_CW1 << FIR_OP4_SHIFT));
+
+                       fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+               } else {
+                       out_be32(&lbc->fir,
+                                (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+                                (FIR_OP_CM2 << FIR_OP1_SHIFT) |
+                                (FIR_OP_CA  << FIR_OP2_SHIFT) |
+                                (FIR_OP_PA  << FIR_OP3_SHIFT) |
+                                (FIR_OP_WB  << FIR_OP4_SHIFT) |
+                                (FIR_OP_CW1 << FIR_OP5_SHIFT));
+
+                       if (column >= mtd->writesize) {
+                               /* OOB area --> READOOB */
+                               column -= mtd->writesize;
+                               fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
+                               ctrl->oob = 1;
+                       } else if (column < 256) {
+                               /* First 256 bytes --> READ0 */
+                               fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+                       } else {
+                               /* Second 256 bytes --> READ1 */
+                               fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT;
+                       }
+               }
+
+               out_be32(&lbc->fcr, fcr);
+               set_addr(mtd, column, page_addr, ctrl->oob);
+               return;
+       }
+
+       /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+       case NAND_CMD_PAGEPROG: {
+               int full_page;
+               dev_vdbg(ctrl->dev,
+                        "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
+                        "writing %d bytes.\n", ctrl->index);
+
+               /* if the write did not start at 0 or is not a full page
+                * then set the exact length, otherwise use a full page
+                * write so the HW generates the ECC.
+                */
+               if (ctrl->oob || ctrl->column != 0 ||
+                   ctrl->index != mtd->writesize + mtd->oobsize) {
+                       out_be32(&lbc->fbcr, ctrl->index);
+                       full_page = 0;
+               } else {
+                       out_be32(&lbc->fbcr, 0);
+                       full_page = 1;
+               }
+
+               fsl_elbc_run_command(mtd);
+
+               /* Read back the page in order to fill in the ECC for the
+                * caller.  Is this really needed?
+                */
+               if (full_page && ctrl->oob_poi) {
+                       out_be32(&lbc->fbcr, 3);
+                       set_addr(mtd, 6, page_addr, 1);
+
+                       ctrl->read_bytes = mtd->writesize + 9;
+
+                       fsl_elbc_do_read(chip, 1);
+                       fsl_elbc_run_command(mtd);
+
+                       memcpy_fromio(ctrl->oob_poi + 6,
+                                     &ctrl->addr[ctrl->index], 3);
+                       ctrl->index += 3;
+               }
+
+               ctrl->oob_poi = NULL;
+               return;
+       }
+
+       /* CMD_STATUS must read the status byte while CEB is active */
+       /* Note - it does not wait for the ready line */
+       case NAND_CMD_STATUS:
+               out_be32(&lbc->fir,
+                        (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+                        (FIR_OP_RBW << FIR_OP1_SHIFT));
+               out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+               out_be32(&lbc->fbcr, 1);
+               set_addr(mtd, 0, 0, 0);
+               ctrl->read_bytes = 1;
+
+               fsl_elbc_run_command(mtd);
+
+               /* The chip always seems to report that it is
+                * write-protected, even when it is not.
+                */
+               setbits8(ctrl->addr, NAND_STATUS_WP);
+               return;
+
+       /* RESET without waiting for the ready line */
+       case NAND_CMD_RESET:
+               dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
+               out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
+               out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
+               fsl_elbc_run_command(mtd);
+               return;
+
+       default:
+               dev_err(ctrl->dev,
+                       "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
+                       command);
+       }
+}
+
+static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
+{
+       /* The hardware does not seem to support multiple
+        * chips per bank.
+        */
+}
+
+/*
+ * Write buf to the FCM Controller Data Buffer
+ */
+static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+       if (len < 0) {
+               dev_err(ctrl->dev, "write_buf of %d bytes", len);
+               ctrl->status = 0;
+               return;
+       }
+
+       if ((unsigned int)len > bufsize - ctrl->index) {
+               dev_err(ctrl->dev,
+                       "write_buf beyond end of buffer "
+                       "(%d requested, %u available)\n",
+                       len, bufsize - ctrl->index);
+               len = bufsize - ctrl->index;
+       }
+
+       memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
+       ctrl->index += len;
+}
+
+/*
+ * read a byte from either the FCM hardware buffer if it has any data left
+ * otherwise issue a command to read a single byte.
+ */
+static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+       /* If there are still bytes in the FCM, then use the next byte. */
+       if (ctrl->index < ctrl->read_bytes)
+               return in_8(&ctrl->addr[ctrl->index++]);
+
+       dev_err(ctrl->dev, "read_byte beyond end of buffer\n");
+       return ERR_BYTE;
+}
+
+/*
+ * Read from the FCM Controller Data Buffer
+ */
+static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       int avail;
+
+       if (len < 0)
+               return;
+
+       avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
+       memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail);
+       ctrl->index += avail;
+
+       if (len > avail)
+               dev_err(ctrl->dev,
+                       "read_buf beyond end of buffer "
+                       "(%d requested, %d available)\n",
+                       len, avail);
+}
+
+/*
+ * Verify buffer against the FCM Controller Data Buffer
+ */
+static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       int i;
+
+       if (len < 0) {
+               dev_err(ctrl->dev, "write_buf of %d bytes", len);
+               return -EINVAL;
+       }
+
+       if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
+               dev_err(ctrl->dev,
+                       "verify_buf beyond end of buffer "
+                       "(%d requested, %u available)\n",
+                       len, ctrl->read_bytes - ctrl->index);
+
+               ctrl->index = ctrl->read_bytes;
+               return -EINVAL;
+       }
+
+       for (i = 0; i < len; i++)
+               if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
+                       break;
+
+       ctrl->index += len;
+       return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
+}
+
+/* This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+
+       if (ctrl->status != LTESR_CC)
+               return NAND_STATUS_FAIL;
+
+       /* Use READ_STATUS command, but wait for the device to be ready */
+       ctrl->use_mdr = 0;
+       out_be32(&lbc->fir,
+                (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+                (FIR_OP_RBW << FIR_OP1_SHIFT));
+       out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+       out_be32(&lbc->fbcr, 1);
+       set_addr(mtd, 0, 0, 0);
+       ctrl->read_bytes = 1;
+
+       fsl_elbc_run_command(mtd);
+
+       if (ctrl->status != LTESR_CC)
+               return NAND_STATUS_FAIL;
+
+       /* The chip always seems to report that it is
+        * write-protected, even when it is not.
+        */
+       setbits8(ctrl->addr, NAND_STATUS_WP);
+       return fsl_elbc_read_byte(mtd);
+}
+
+static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+       unsigned int al;
+
+       /* calculate FMR Address Length field */
+       al = 0;
+       if (chip->pagemask & 0xffff0000)
+               al++;
+       if (chip->pagemask & 0xff000000)
+               al++;
+
+       /* add to ECCM mode set in fsl_elbc_init */
+       priv->fmr |= (12 << FMR_CWTO_SHIFT) |  /* Timeout > 12 ms */
+                    (al << FMR_AL_SHIFT);
+
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n",
+               chip->numchips);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %ld\n",
+               chip->chipsize);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
+               chip->pagemask);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
+               chip->chip_delay);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
+               chip->badblockpos);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
+               chip->chip_shift);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n",
+               chip->page_shift);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
+               chip->phys_erase_shift);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
+               chip->ecclayout);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
+               chip->ecc.mode);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
+               chip->ecc.steps);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
+               chip->ecc.bytes);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
+               chip->ecc.total);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
+               chip->ecc.layout);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %d\n", mtd->size);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
+               mtd->erasesize);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n",
+               mtd->writesize);
+       dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
+               mtd->oobsize);
+
+       /* adjust Option Register and ECC to match Flash page size */
+       if (mtd->writesize == 512) {
+               priv->page_size = 0;
+               clrbits32(&lbc->bank[priv->bank].or, ~OR_FCM_PGS);
+       } else if (mtd->writesize == 2048) {
+               priv->page_size = 1;
+               setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+               /* adjust ecc setup if needed */
+               if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+                   BR_DECC_CHK_GEN) {
+                       chip->ecc.size = 512;
+                       chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
+                                          &fsl_elbc_oob_lp_eccm1 :
+                                          &fsl_elbc_oob_lp_eccm0;
+                       mtd->ecclayout = chip->ecc.layout;
+                       mtd->oobavail = chip->ecc.layout->oobavail;
+               }
+       } else {
+               dev_err(ctrl->dev,
+                       "fsl_elbc_init: page size %d is not supported\n",
+                       mtd->writesize);
+               return -1;
+       }
+
+       /* The default u-boot configuration on MPC8313ERDB causes errors;
+        * more delay is needed.  This should be safe for other boards
+        * as well.
+        */
+       setbits32(&lbc->bank[priv->bank].or, 0x70);
+       return 0;
+}
+
+static int fsl_elbc_read_page(struct mtd_info *mtd,
+                              struct nand_chip *chip,
+                              uint8_t *buf)
+{
+       fsl_elbc_read_buf(mtd, buf, mtd->writesize);
+       fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
+               mtd->ecc_stats.failed++;
+
+       return 0;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static void fsl_elbc_write_page(struct mtd_info *mtd,
+                                struct nand_chip *chip,
+                                const uint8_t *buf)
+{
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+       fsl_elbc_write_buf(mtd, buf, mtd->writesize);
+       fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       ctrl->oob_poi = chip->oob_poi;
+}
+
+static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
+{
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+       struct nand_chip *chip = &priv->chip;
+
+       dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
+
+       /* Fill in fsl_elbc_mtd structure */
+       priv->mtd.priv = chip;
+       priv->mtd.owner = THIS_MODULE;
+       priv->fmr = 0; /* rest filled in later */
+
+       /* fill in nand_chip structure */
+       /* set up function call table */
+       chip->read_byte = fsl_elbc_read_byte;
+       chip->write_buf = fsl_elbc_write_buf;
+       chip->read_buf = fsl_elbc_read_buf;
+       chip->verify_buf = fsl_elbc_verify_buf;
+       chip->select_chip = fsl_elbc_select_chip;
+       chip->cmdfunc = fsl_elbc_cmdfunc;
+       chip->waitfunc = fsl_elbc_wait;
+
+       /* set up nand options */
+       chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
+
+       chip->controller = &ctrl->controller;
+       chip->priv = priv;
+
+       chip->ecc.read_page = fsl_elbc_read_page;
+       chip->ecc.write_page = fsl_elbc_write_page;
+
+       /* If CS Base Register selects full hardware ECC then use it */
+       if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+           BR_DECC_CHK_GEN) {
+               chip->ecc.mode = NAND_ECC_HW;
+               /* put in small page settings and adjust later if needed */
+               chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
+                               &fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
+               chip->ecc.size = 512;
+               chip->ecc.bytes = 3;
+       } else {
+               /* otherwise fall back to default software ECC */
+               chip->ecc.mode = NAND_ECC_SOFT;
+       }
+
+       return 0;
+}
+
+static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
+{
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+       nand_release(&priv->mtd);
+
+       if (priv->vbase)
+               iounmap(priv->vbase);
+
+       ctrl->chips[priv->bank] = NULL;
+       kfree(priv);
+
+       return 0;
+}
+
+static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
+                               struct device_node *node)
+{
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+       struct fsl_elbc_mtd *priv;
+       struct resource res;
+#ifdef CONFIG_MTD_PARTITIONS
+       static const char *part_probe_types[]
+               = { "cmdlinepart", "RedBoot", NULL };
+       struct mtd_partition *parts;
+#endif
+       int ret;
+       int bank;
+
+       /* get, allocate and map the memory resource */
+       ret = of_address_to_resource(node, 0, &res);
+       if (ret) {
+               dev_err(ctrl->dev, "failed to get resource\n");
+               return ret;
+       }
+
+       /* find which chip select it is connected to */
+       for (bank = 0; bank < MAX_BANKS; bank++)
+               if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
+                   (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
+                   (in_be32(&lbc->bank[bank].br) &
+                    in_be32(&lbc->bank[bank].or) & BR_BA)
+                    == res.start)
+                       break;
+
+       if (bank >= MAX_BANKS) {
+               dev_err(ctrl->dev, "address did not match any chip selects\n");
+               return -ENODEV;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       ctrl->chips[bank] = priv;
+       priv->bank = bank;
+       priv->ctrl = ctrl;
+       priv->dev = ctrl->dev;
+
+       priv->vbase = ioremap(res.start, res.end - res.start + 1);
+       if (!priv->vbase) {
+               dev_err(ctrl->dev, "failed to map chip region\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = fsl_elbc_chip_init(priv);
+       if (ret)
+               goto err;
+
+       ret = nand_scan_ident(&priv->mtd, 1);
+       if (ret)
+               goto err;
+
+       ret = fsl_elbc_chip_init_tail(&priv->mtd);
+       if (ret)
+               goto err;
+
+       ret = nand_scan_tail(&priv->mtd);
+       if (ret)
+               goto err;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       /* First look for RedBoot table or partitions on the command
+        * line, these take precedence over device tree information */
+       ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, 0);
+       if (ret < 0)
+               goto err;
+
+#ifdef CONFIG_MTD_OF_PARTS
+       if (ret == 0) {
+               ret = of_mtd_parse_partitions(priv->dev, &priv->mtd,
+                                             node, &parts);
+               if (ret < 0)
+                       goto err;
+       }
+#endif
+
+       if (ret > 0)
+               add_mtd_partitions(&priv->mtd, parts, ret);
+       else
+#endif
+               add_mtd_device(&priv->mtd);
+
+       printk(KERN_INFO "eLBC NAND device at 0x%zx, bank %d\n",
+              res.start, priv->bank);
+       return 0;
+
+err:
+       fsl_elbc_chip_remove(priv);
+       return ret;
+}
+
+static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl)
+{
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+
+       /* clear event registers */
+       setbits32(&lbc->ltesr, LTESR_NAND_MASK);
+       out_be32(&lbc->lteatr, 0);
+
+       /* Enable interrupts for any detected events */
+       out_be32(&lbc->lteir, LTESR_NAND_MASK);
+
+       ctrl->read_bytes = 0;
+       ctrl->index = 0;
+       ctrl->addr = NULL;
+
+       return 0;
+}
+
+static int __devexit fsl_elbc_ctrl_remove(struct of_device *ofdev)
+{
+       struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev);
+       int i;
+
+       for (i = 0; i < MAX_BANKS; i++)
+               if (ctrl->chips[i])
+                       fsl_elbc_chip_remove(ctrl->chips[i]);
+
+       if (ctrl->irq)
+               free_irq(ctrl->irq, ctrl);
+
+       if (ctrl->regs)
+               iounmap(ctrl->regs);
+
+       dev_set_drvdata(&ofdev->dev, NULL);
+       kfree(ctrl);
+       return 0;
+}
+
+/* NOTE: This interrupt is also used to report other localbus events,
+ * such as transaction errors on other chipselects.  If we want to
+ * capture those, we'll need to move the IRQ code into a shared
+ * LBC driver.
+ */
+
+static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data)
+{
+       struct fsl_elbc_ctrl *ctrl = data;
+       struct elbc_regs __iomem *lbc = ctrl->regs;
+       __be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK;
+
+       if (status) {
+               out_be32(&lbc->ltesr, status);
+               out_be32(&lbc->lteatr, 0);
+
+               ctrl->irq_status = status;
+               smp_wmb();
+               wake_up(&ctrl->irq_wait);
+
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+/* fsl_elbc_ctrl_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code allocates all of
+ * the resources needed for the controller only.  The
+ * resources for the NAND banks themselves are allocated
+ * in the chip probe function.
+*/
+
+static int __devinit fsl_elbc_ctrl_probe(struct of_device *ofdev,
+                                         const struct of_device_id *match)
+{
+       struct device_node *child;
+       struct fsl_elbc_ctrl *ctrl;
+       int ret;
+
+       ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+       if (!ctrl)
+               return -ENOMEM;
+
+       dev_set_drvdata(&ofdev->dev, ctrl);
+
+       spin_lock_init(&ctrl->controller.lock);
+       init_waitqueue_head(&ctrl->controller.wq);
+       init_waitqueue_head(&ctrl->irq_wait);
+
+       ctrl->regs = of_iomap(ofdev->node, 0);
+       if (!ctrl->regs) {
+               dev_err(&ofdev->dev, "failed to get memory region\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       ctrl->irq = of_irq_to_resource(ofdev->node, 0, NULL);
+       if (ctrl->irq == NO_IRQ) {
+               dev_err(&ofdev->dev, "failed to get irq resource\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       ctrl->dev = &ofdev->dev;
+
+       ret = fsl_elbc_ctrl_init(ctrl);
+       if (ret < 0)
+               goto err;
+
+       ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl);
+       if (ret != 0) {
+               dev_err(&ofdev->dev, "failed to install irq (%d)\n",
+                       ctrl->irq);
+               ret = ctrl->irq;
+               goto err;
+       }
+
+       for_each_child_of_node(ofdev->node, child)
+               if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
+                       fsl_elbc_chip_probe(ctrl, child);
+
+       return 0;
+
+err:
+       fsl_elbc_ctrl_remove(ofdev);
+       return ret;
+}
+
+static const struct of_device_id fsl_elbc_match[] = {
+       {
+               .compatible = "fsl,elbc",
+       },
+       {}
+};
+
+static struct of_platform_driver fsl_elbc_ctrl_driver = {
+       .driver = {
+               .name   = "fsl-elbc",
+       },
+       .match_table = fsl_elbc_match,
+       .probe = fsl_elbc_ctrl_probe,
+       .remove = __devexit_p(fsl_elbc_ctrl_remove),
+};
+
+static int __init fsl_elbc_init(void)
+{
+       return of_register_platform_driver(&fsl_elbc_ctrl_driver);
+}
+
+static void __exit fsl_elbc_exit(void)
+{
+       of_unregister_platform_driver(&fsl_elbc_ctrl_driver);
+}
+
+module_init(fsl_elbc_init);
+module_exit(fsl_elbc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
index ddd4fc019042ff72250c887944a3410ec6b69459..7acb1a0e7409fbf950a06e97f8e58b3a1be38559 100644 (file)
@@ -2469,8 +2469,12 @@ int nand_scan_tail(struct mtd_info *mtd)
                        chip->ecc.write_oob = nand_write_oob_std;
 
        case NAND_ECC_HW_SYNDROME:
-               if (!chip->ecc.calculate || !chip->ecc.correct ||
-                   !chip->ecc.hwctl) {
+               if ((!chip->ecc.calculate || !chip->ecc.correct ||
+                    !chip->ecc.hwctl) &&
+                   (!chip->ecc.read_page ||
+                    chip->ecc.read_page == nand_read_page_hwecc ||
+                    !chip->ecc.write_page ||
+                    chip->ecc.write_page == nand_write_page_hwecc)) {
                        printk(KERN_WARNING "No ECC functions supplied, "
                               "Hardware ECC not possible\n");
                        BUG();
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
new file mode 100644 (file)
index 0000000..9162cca
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * drivers/mtd/nand/orion_nand.c
+ *
+ * NAND support for Marvell Orion SoC platforms
+ *
+ * Tzachi Perelstein <tzachi@marvell.com>
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/arch/platform.h>
+#include <asm/arch/hardware.h>
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+       struct nand_chip *nc = mtd->priv;
+       struct orion_nand_data *board = nc->priv;
+       u32 offs;
+
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       if (ctrl & NAND_CLE)
+               offs = (1 << board->cle);
+       else if (ctrl & NAND_ALE)
+               offs = (1 << board->ale);
+       else
+               return;
+
+       if (nc->options & NAND_BUSWIDTH_16)
+               offs <<= 1;
+
+       writeb(cmd, nc->IO_ADDR_W + offs);
+}
+
+static int __init orion_nand_probe(struct platform_device *pdev)
+{
+       struct mtd_info *mtd;
+       struct nand_chip *nc;
+       struct orion_nand_data *board;
+       void __iomem *io_base;
+       int ret = 0;
+#ifdef CONFIG_MTD_PARTITIONS
+       struct mtd_partition *partitions = NULL;
+       int num_part = 0;
+#endif
+
+       nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
+       if (!nc) {
+               printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");
+               ret = -ENOMEM;
+               goto no_res;
+       }
+       mtd = (struct mtd_info *)(nc + 1);
+
+       io_base = ioremap(pdev->resource[0].start,
+                       pdev->resource[0].end - pdev->resource[0].start + 1);
+       if (!io_base) {
+               printk(KERN_ERR "orion_nand: ioremap failed\n");
+               ret = -EIO;
+               goto no_res;
+       }
+
+       board = pdev->dev.platform_data;
+
+       mtd->priv = nc;
+       mtd->owner = THIS_MODULE;
+
+       nc->priv = board;
+       nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
+       nc->cmd_ctrl = orion_nand_cmd_ctrl;
+       nc->ecc.mode = NAND_ECC_SOFT;
+
+       if (board->width == 16)
+               nc->options |= NAND_BUSWIDTH_16;
+
+       platform_set_drvdata(pdev, mtd);
+
+       if (nand_scan(mtd, 1)) {
+               ret = -ENXIO;
+               goto no_dev;
+       }
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+       mtd->name = "orion_nand";
+       num_part = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
+#endif
+       /* If cmdline partitions have been passed, let them be used */
+       if (num_part <= 0) {
+               num_part = board->nr_parts;
+               partitions = board->parts;
+       }
+
+       if (partitions && num_part > 0)
+               ret = add_mtd_partitions(mtd, partitions, num_part);
+       else
+               ret = add_mtd_device(mtd);
+#else
+       ret = add_mtd_device(mtd);
+#endif
+
+       if (ret) {
+               nand_release(mtd);
+               goto no_dev;
+       }
+
+       return 0;
+
+no_dev:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(io_base);
+no_res:
+       kfree(nc);
+
+       return ret;
+}
+
+static int __devexit orion_nand_remove(struct platform_device *pdev)
+{
+       struct mtd_info *mtd = platform_get_drvdata(pdev);
+       struct nand_chip *nc = mtd->priv;
+
+       nand_release(mtd);
+
+       iounmap(nc->IO_ADDR_W);
+
+       kfree(nc);
+
+       return 0;
+}
+
+static struct platform_driver orion_nand_driver = {
+       .probe          = orion_nand_probe,
+       .remove         = orion_nand_remove,
+       .driver         = {
+               .name   = "orion_nand",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init orion_nand_init(void)
+{
+       return platform_driver_register(&orion_nand_driver);
+}
+
+static void __exit orion_nand_exit(void)
+{
+       platform_driver_unregister(&orion_nand_driver);
+}
+
+module_init(orion_nand_init);
+module_exit(orion_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tzachi Perelstein");
+MODULE_DESCRIPTION("NAND glue for Orion platforms");
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
new file mode 100644 (file)
index 0000000..75c8990
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Egor Martovetsky <egor@pasemi.com>
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip NAND flash interface
+ *
+ * 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 the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#undef DEBUG
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+
+#define LBICTRL_LPCCTL_NR              0x00004000
+#define CLE_PIN_CTL                    15
+#define ALE_PIN_CTL                    14
+
+static unsigned int lpcctl;
+static struct mtd_info *pasemi_nand_mtd;
+static const char driver_name[] = "pasemi-nand";
+
+static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       while (len > 0x800) {
+               memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
+               buf += 0x800;
+               len -= 0x800;
+       }
+       memcpy_fromio(buf, chip->IO_ADDR_R, len);
+}
+
+static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       while (len > 0x800) {
+               memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
+               buf += 0x800;
+               len -= 0x800;
+       }
+       memcpy_toio(chip->IO_ADDR_R, buf, len);
+}
+
+static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
+                            unsigned int ctrl)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       if (ctrl & NAND_CLE)
+               out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
+       else
+               out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
+
+       /* Push out posted writes */
+       eieio();
+       inl(lpcctl);
+}
+
+int pasemi_device_ready(struct mtd_info *mtd)
+{
+       return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
+}
+
+static int __devinit pasemi_nand_probe(struct of_device *ofdev,
+                                     const struct of_device_id *match)
+{
+       struct pci_dev *pdev;
+       struct device_node *np = ofdev->node;
+       struct resource res;
+       struct nand_chip *chip;
+       int err = 0;
+
+       err = of_address_to_resource(np, 0, &res);
+
+       if (err)
+               return -EINVAL;
+
+       /* We only support one device at the moment */
+       if (pasemi_nand_mtd)
+               return -ENODEV;
+
+       pr_debug("pasemi_nand at %lx-%lx\n", res.start, res.end);
+
+       /* Allocate memory for MTD device structure and private data */
+       pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) +
+                                 sizeof(struct nand_chip), GFP_KERNEL);
+       if (!pasemi_nand_mtd) {
+               printk(KERN_WARNING
+                      "Unable to allocate PASEMI NAND MTD device structure\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Get pointer to private data */
+       chip = (struct nand_chip *)&pasemi_nand_mtd[1];
+
+       /* Link the private data with the MTD structure */
+       pasemi_nand_mtd->priv = chip;
+       pasemi_nand_mtd->owner = THIS_MODULE;
+
+       chip->IO_ADDR_R = of_iomap(np, 0);
+       chip->IO_ADDR_W = chip->IO_ADDR_R;
+
+       if (!chip->IO_ADDR_R) {
+               err = -EIO;
+               goto out_mtd;
+       }
+
+       pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa008, NULL);
+       if (!pdev) {
+               err = -ENODEV;
+               goto out_ior;
+       }
+
+       lpcctl = pci_resource_start(pdev, 0);
+
+       if (!request_region(lpcctl, 4, driver_name)) {
+               err = -EBUSY;
+               goto out_ior;
+       }
+
+       chip->cmd_ctrl = pasemi_hwcontrol;
+       chip->dev_ready = pasemi_device_ready;
+       chip->read_buf = pasemi_read_buf;
+       chip->write_buf = pasemi_write_buf;
+       chip->chip_delay = 0;
+       chip->ecc.mode = NAND_ECC_SOFT;
+
+       /* Enable the following for a flash based bad block table */
+       chip->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR;
+
+       /* Scan to find existance of the device */
+       if (nand_scan(pasemi_nand_mtd, 1)) {
+               err = -ENXIO;
+               goto out_lpc;
+       }
+
+       if (add_mtd_device(pasemi_nand_mtd)) {
+               printk(KERN_ERR "pasemi_nand: Unable to register MTD device\n");
+               err = -ENODEV;
+               goto out_lpc;
+       }
+
+       printk(KERN_INFO "PA Semi NAND flash at %08lx, control at I/O %x\n",
+              res.start, lpcctl);
+
+       return 0;
+
+ out_lpc:
+       release_region(lpcctl, 4);
+ out_ior:
+       iounmap(chip->IO_ADDR_R);
+ out_mtd:
+       kfree(pasemi_nand_mtd);
+ out:
+       return err;
+}
+
+static int __devexit pasemi_nand_remove(struct of_device *ofdev)
+{
+       struct nand_chip *chip;
+
+       if (!pasemi_nand_mtd)
+               return 0;
+
+       chip = pasemi_nand_mtd->priv;
+
+       /* Release resources, unregister device */
+       nand_release(pasemi_nand_mtd);
+
+       release_region(lpcctl, 4);
+
+       iounmap(chip->IO_ADDR_R);
+
+       /* Free the MTD device structure */
+       kfree(pasemi_nand_mtd);
+
+       pasemi_nand_mtd = NULL;
+
+       return 0;
+}
+
+static struct of_device_id pasemi_nand_match[] =
+{
+       {
+               .compatible   = "pasemi,localbus-nand",
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, pasemi_nand_match);
+
+static struct of_platform_driver pasemi_nand_driver =
+{
+       .name           = (char*)driver_name,
+       .match_table    = pasemi_nand_match,
+       .probe          = pasemi_nand_probe,
+       .remove         = pasemi_nand_remove,
+};
+
+static int __init pasemi_nand_init(void)
+{
+       return of_register_platform_driver(&pasemi_nand_driver);
+}
+module_init(pasemi_nand_init);
+
+static void __exit pasemi_nand_exit(void)
+{
+       of_unregister_platform_driver(&pasemi_nand_driver);
+}
+module_exit(pasemi_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("NAND flash interface driver for PA Semi PWRficient");
index cd725fc5e813e7b11f03207944fbb14be33229a6..f6d5c2adc4fd41171c892859b96e85c10f45c369 100644 (file)
@@ -110,7 +110,9 @@ out:
 static int __devexit plat_nand_remove(struct platform_device *pdev)
 {
        struct plat_nand_data *data = platform_get_drvdata(pdev);
+#ifdef CONFIG_MTD_PARTITIONS
        struct platform_nand_data *pdata = pdev->dev.platform_data;
+#endif
 
        nand_release(&data->mtd);
 #ifdef CONFIG_MTD_PARTITIONS
index 2bd0737572c6fe9146a5b26d6f4147a2e76daea8..9260ad947524f4f4a28959a3b843f48a8069c7f8 100644 (file)
@@ -120,6 +120,8 @@ struct s3c2410_nand_info {
        int                             sel_bit;
        int                             mtd_count;
 
+       unsigned long                   save_nfconf;
+
        enum s3c_cpu_type               cpu_type;
 };
 
@@ -364,23 +366,21 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
            ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
                /* calculate the bit position of the error */
 
-               bit  = (diff2 >> 2) & 1;
-               bit |= (diff2 >> 3) & 2;
-               bit |= (diff2 >> 4) & 4;
+               bit  = ((diff2 >> 3) & 1) |
+                      ((diff2 >> 4) & 2) |
+                      ((diff2 >> 5) & 4);
 
                /* calculate the byte position of the error */
 
-               byte  = (diff1 << 1) & 0x80;
-               byte |= (diff1 << 2) & 0x40;
-               byte |= (diff1 << 3) & 0x20;
-               byte |= (diff1 << 4) & 0x10;
-
-               byte |= (diff0 >> 3) & 0x08;
-               byte |= (diff0 >> 2) & 0x04;
-               byte |= (diff0 >> 1) & 0x02;
-               byte |= (diff0 >> 0) & 0x01;
-
-               byte |= (diff2 << 8) & 0x100;
+               byte = ((diff2 << 7) & 0x100) |
+                      ((diff1 << 0) & 0x80)  |
+                      ((diff1 << 1) & 0x40)  |
+                      ((diff1 << 2) & 0x20)  |
+                      ((diff1 << 3) & 0x10)  |
+                      ((diff0 >> 4) & 0x08)  |
+                      ((diff0 >> 3) & 0x04)  |
+                      ((diff0 >> 2) & 0x02)  |
+                      ((diff0 >> 1) & 0x01);
 
                dev_dbg(info->device, "correcting error bit %d, byte %d\n",
                        bit, byte);
@@ -399,7 +399,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
        if ((diff0 & ~(1<<fls(diff0))) == 0)
                return 1;
 
-       return 0;
+       return -1;
 }
 
 /* ECC functions
@@ -810,6 +810,16 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
        struct s3c2410_nand_info *info = platform_get_drvdata(dev);
 
        if (info) {
+               info->save_nfconf = readl(info->regs + S3C2410_NFCONF);
+
+               /* For the moment, we must ensure nFCE is high during
+                * the time we are suspended. This really should be
+                * handled by suspending the MTDs we are using, but
+                * that is currently not the case. */
+
+               writel(info->save_nfconf | info->sel_bit,
+                      info->regs + S3C2410_NFCONF);
+
                if (!allow_clk_stop(info))
                        clk_disable(info->clk);
        }
@@ -820,11 +830,19 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
 static int s3c24xx_nand_resume(struct platform_device *dev)
 {
        struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+       unsigned long nfconf;
 
        if (info) {
                clk_enable(info->clk);
                s3c2410_nand_inithw(info, dev);
 
+               /* Restore the state of the nFCE line. */
+
+               nfconf = readl(info->regs + S3C2410_NFCONF);
+               nfconf &= ~info->sel_bit;
+               nfconf |= info->save_nfconf & info->sel_bit;
+               writel(nfconf, info->regs + S3C2410_NFCONF);
+
                if (allow_clk_stop(info))
                        clk_disable(info->clk);
        }
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
new file mode 100644 (file)
index 0000000..f86e069
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Flash partitions described by the OF (or flattened) device tree
+ *
+ * Copyright (C) 2006 MontaVista Software Inc.
+ * Author: Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * Revised to handle newer style flash binding by:
+ *   Copyright (C) 2007 David Gibson, IBM Corporation.
+ *
+ * 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/init.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+int __devinit of_mtd_parse_partitions(struct device *dev,
+                                      struct mtd_info *mtd,
+                                      struct device_node *node,
+                                      struct mtd_partition **pparts)
+{
+       const char *partname;
+       struct device_node *pp;
+       int nr_parts, i;
+
+       /* First count the subnodes */
+       pp = NULL;
+       nr_parts = 0;
+       while ((pp = of_get_next_child(node, pp)))
+               nr_parts++;
+
+       if (nr_parts == 0)
+               return 0;
+
+       *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
+       if (!*pparts)
+               return -ENOMEM;
+
+       pp = NULL;
+       i = 0;
+       while ((pp = of_get_next_child(node, pp))) {
+               const u32 *reg;
+               int len;
+
+               reg = of_get_property(pp, "reg", &len);
+               if (!reg || (len != 2 * sizeof(u32))) {
+                       of_node_put(pp);
+                       dev_err(dev, "Invalid 'reg' on %s\n", node->full_name);
+                       kfree(*pparts);
+                       *pparts = NULL;
+                       return -EINVAL;
+               }
+               (*pparts)[i].offset = reg[0];
+               (*pparts)[i].size = reg[1];
+
+               partname = of_get_property(pp, "label", &len);
+               if (!partname)
+                       partname = of_get_property(pp, "name", &len);
+               (*pparts)[i].name = (char *)partname;
+
+               if (of_get_property(pp, "read-only", &len))
+                       (*pparts)[i].mask_flags = MTD_WRITEABLE;
+
+               i++;
+       }
+
+       return nr_parts;
+}
+EXPORT_SYMBOL(of_mtd_parse_partitions);
index 1b0b3201141592f130d2ee6433194476cc36f2bd..8d7d21be1541867aca5a494b3965d49c6316c0bd 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/mtd/mtd.h>
@@ -169,6 +170,18 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
        return ((bsa << ONENAND_BSA_SHIFT) | bsc);
 }
 
+/**
+ * onenand_get_density - [DEFAULT] Get OneNAND density
+ * @param dev_id       OneNAND device ID
+ *
+ * Get OneNAND density from device ID
+ */
+static inline int onenand_get_density(int dev_id)
+{
+       int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       return (density & ONENAND_DEVICE_DENSITY_MASK);
+}
+
 /**
  * onenand_command - [DEFAULT] Send command to OneNAND device
  * @param mtd          MTD device structure
@@ -182,8 +195,7 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
 static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len)
 {
        struct onenand_chip *this = mtd->priv;
-       int value, readcmd = 0, block_cmd = 0;
-       int block, page;
+       int value, block, page;
 
        /* Address translation */
        switch (cmd) {
@@ -198,7 +210,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
        case ONENAND_CMD_ERASE:
        case ONENAND_CMD_BUFFERRAM:
        case ONENAND_CMD_OTP_ACCESS:
-               block_cmd = 1;
                block = (int) (addr >> this->erase_shift);
                page = -1;
                break;
@@ -240,11 +251,9 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
                value = onenand_block_address(this, block);
                this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
 
-               if (block_cmd) {
-                       /* Select DataRAM for DDP */
-                       value = onenand_bufferram_address(this, block);
-                       this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
-               }
+               /* Select DataRAM for DDP */
+               value = onenand_bufferram_address(this, block);
+               this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
        }
 
        if (page != -1) {
@@ -256,7 +265,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
                case ONENAND_CMD_READ:
                case ONENAND_CMD_READOOB:
                        dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
-                       readcmd = 1;
                        break;
 
                default:
@@ -273,12 +281,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
                /* Write 'BSA, BSC' of DataRAM */
                value = onenand_buffer_address(dataram, sectors, count);
                this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
-
-               if (readcmd) {
-                       /* Select DataRAM for DDP */
-                       value = onenand_bufferram_address(this, block);
-                       this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
-               }
        }
 
        /* Interrupt clear */
@@ -855,6 +857,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                        this->command(mtd, ONENAND_CMD_READ, from, writesize);
                        ret = this->wait(mtd, FL_READING);
                        onenand_update_bufferram(mtd, from, !ret);
+                       if (ret == -EBADMSG)
+                               ret = 0;
                }
        }
 
@@ -913,6 +917,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                /* Now wait for load */
                ret = this->wait(mtd, FL_READING);
                onenand_update_bufferram(mtd, from, !ret);
+               if (ret == -EBADMSG)
+                       ret = 0;
        }
 
        /*
@@ -923,12 +929,12 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
        ops->retlen = read;
        ops->oobretlen = oobread;
 
-       if (mtd->ecc_stats.failed - stats.failed)
-               return -EBADMSG;
-
        if (ret)
                return ret;
 
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
+
        return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
 }
 
@@ -944,6 +950,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
                        struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
+       struct mtd_ecc_stats stats;
        int read = 0, thislen, column, oobsize;
        size_t len = ops->ooblen;
        mtd_oob_mode_t mode = ops->mode;
@@ -977,6 +984,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
                return -EINVAL;
        }
 
+       stats = mtd->ecc_stats;
+
        while (read < len) {
                cond_resched();
 
@@ -988,18 +997,16 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
                onenand_update_bufferram(mtd, from, 0);
 
                ret = this->wait(mtd, FL_READING);
-               /* First copy data and check return value for ECC handling */
+               if (ret && ret != -EBADMSG) {
+                       printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
+                       break;
+               }
 
                if (mode == MTD_OOB_AUTO)
                        onenand_transfer_auto_oob(mtd, buf, column, thislen);
                else
                        this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
 
-               if (ret) {
-                       printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
-                       break;
-               }
-
                read += thislen;
 
                if (read == len)
@@ -1016,7 +1023,14 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
        }
 
        ops->oobretlen = read;
-       return ret;
+
+       if (ret)
+               return ret;
+
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
+
+       return 0;
 }
 
 /**
@@ -1106,12 +1120,10 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
        interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
        ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
 
+       /* Initial bad block case: 0x2400 or 0x0400 */
        if (ctrl & ONENAND_CTRL_ERROR) {
                printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
-               /* Initial bad block case */
-               if (ctrl & ONENAND_CTRL_LOAD)
-                       return ONENAND_BBT_READ_ERROR;
-               return ONENAND_BBT_READ_FATAL_ERROR;
+               return ONENAND_BBT_READ_ERROR;
        }
 
        if (interrupt & ONENAND_INT_READ) {
@@ -1206,7 +1218,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
 static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
 {
        struct onenand_chip *this = mtd->priv;
-       char oobbuf[64];
+       u_char *oob_buf = this->oob_buf;
        int status, i;
 
        this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
@@ -1215,9 +1227,9 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
        if (status)
                return status;
 
-       this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
+       this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
        for (i = 0; i < mtd->oobsize; i++)
-               if (buf[i] != 0xFF && buf[i] != oobbuf[i])
+               if (buf[i] != 0xFF && buf[i] != oob_buf[i])
                        return -EBADMSG;
 
        return 0;
@@ -1273,6 +1285,112 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
 
 #define NOTALIGNED(x)  ((x & (this->subpagesize - 1)) != 0)
 
+static void onenand_panic_wait(struct mtd_info *mtd)
+{
+       struct onenand_chip *this = mtd->priv;
+       unsigned int interrupt;
+       int i;
+       
+       for (i = 0; i < 2000; i++) {
+               interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+               if (interrupt & ONENAND_INT_MASTER)
+                       break;
+               udelay(10);
+       }
+}
+
+/**
+ * onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context
+ * @param mtd          MTD device structure
+ * @param to           offset to write to
+ * @param len          number of bytes to write
+ * @param retlen       pointer to variable to store the number of written bytes
+ * @param buf          the data to write
+ *
+ * Write with ECC
+ */
+static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
+                        size_t *retlen, const u_char *buf)
+{
+       struct onenand_chip *this = mtd->priv;
+       int column, subpage;
+       int written = 0;
+       int ret = 0;
+
+       if (this->state == FL_PM_SUSPENDED)
+               return -EBUSY;
+
+       /* Wait for any existing operation to clear */
+       onenand_panic_wait(mtd);
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_panic_write: to = 0x%08x, len = %i\n",
+             (unsigned int) to, (int) len);
+
+       /* Initialize retlen, in case of early exit */
+       *retlen = 0;
+
+       /* Do not allow writes past end of device */
+       if (unlikely((to + len) > mtd->size)) {
+               printk(KERN_ERR "onenand_panic_write: Attempt write to past end of device\n");
+               return -EINVAL;
+       }
+
+       /* Reject writes, which are not page aligned */
+        if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
+                printk(KERN_ERR "onenand_panic_write: Attempt to write not page aligned data\n");
+                return -EINVAL;
+        }
+
+       column = to & (mtd->writesize - 1);
+
+       /* Loop until all data write */
+       while (written < len) {
+               int thislen = min_t(int, mtd->writesize - column, len - written);
+               u_char *wbuf = (u_char *) buf;
+
+               this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
+
+               /* Partial page write */
+               subpage = thislen < mtd->writesize;
+               if (subpage) {
+                       memset(this->page_buf, 0xff, mtd->writesize);
+                       memcpy(this->page_buf + column, buf, thislen);
+                       wbuf = this->page_buf;
+               }
+
+               this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
+               this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
+
+               this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
+
+               onenand_panic_wait(mtd);
+
+               /* In partial page write we don't update bufferram */
+               onenand_update_bufferram(mtd, to, !ret && !subpage);
+               if (ONENAND_IS_2PLANE(this)) {
+                       ONENAND_SET_BUFFERRAM1(this);
+                       onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
+               }
+
+               if (ret) {
+                       printk(KERN_ERR "onenand_panic_write: write failed %d\n", ret);
+                       break;
+               }
+
+               written += thislen;
+
+               if (written == len)
+                       break;
+
+               column = 0;
+               to += thislen;
+               buf += thislen;
+       }
+
+       *retlen = written;
+       return ret;
+}
+
 /**
  * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
  * @param mtd          MTD device structure
@@ -1419,7 +1537,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
                }
 
                /* Only check verify write turn on */
-               ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
+               ret = onenand_verify(mtd, buf, to, thislen);
                if (ret) {
                        printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
                        break;
@@ -1435,9 +1553,6 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
                buf += thislen;
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
-
        ops->retlen = written;
 
        return ret;
@@ -2148,7 +2263,7 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
 
        *retlen = 0;
 
-       density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       density = onenand_get_density(this->device_id);
        if (density < ONENAND_DEVICE_DENSITY_512Mb)
                otp_pages = 20;
        else
@@ -2299,7 +2414,8 @@ static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
 static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
                        size_t len)
 {
-       unsigned char oob_buf[64];
+       struct onenand_chip *this = mtd->priv;
+       u_char *oob_buf = this->oob_buf;
        size_t retlen;
        int ret;
 
@@ -2339,7 +2455,7 @@ static void onenand_check_features(struct mtd_info *mtd)
        unsigned int density, process;
 
        /* Lock scheme depends on density and process */
-       density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       density = onenand_get_density(this->device_id);
        process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
 
        /* Lock scheme */
@@ -2388,7 +2504,7 @@ static void onenand_print_device_info(int device, int version)
         vcc = device & ONENAND_DEVICE_VCC_MASK;
         demuxed = device & ONENAND_DEVICE_IS_DEMUX;
         ddp = device & ONENAND_DEVICE_IS_DDP;
-        density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
+        density = onenand_get_density(device);
         printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",
                 demuxed ? "" : "Muxed ",
                 ddp ? "(DDP)" : "",
@@ -2480,7 +2596,7 @@ static int onenand_probe(struct mtd_info *mtd)
        this->device_id = dev_id;
        this->version_id = ver_id;
 
-       density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       density = onenand_get_density(dev_id);
        this->chipsize = (16 << density) << 20;
        /* Set density mask. it is used for DDP */
        if (ONENAND_IS_DDP(this))
@@ -2664,6 +2780,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
        mtd->write = onenand_write;
        mtd->read_oob = onenand_read_oob;
        mtd->write_oob = onenand_write_oob;
+       mtd->panic_write = onenand_panic_write;
 #ifdef CONFIG_MTD_ONENAND_OTP
        mtd->get_fact_prot_info = onenand_get_fact_prot_info;
        mtd->read_fact_prot_reg = onenand_read_fact_prot_reg;
index a61351f88ec046d894bf07bc042907e2a22bb364..47474903263c377555b0a5c0fefad3af737c1c78 100644 (file)
@@ -59,16 +59,31 @@ static int parse_redboot_partitions(struct mtd_info *master,
        static char nullstring[] = "unallocated";
 #endif
 
+       if ( directory < 0 ) {
+               offset = master->size + directory * master->erasesize;
+               while (master->block_isbad && 
+                      master->block_isbad(master, offset)) {
+                       if (!offset) {
+                       nogood:
+                               printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
+                               return -EIO;
+                       }
+                       offset -= master->erasesize;
+               }
+       } else {
+               offset = directory * master->erasesize;
+               while (master->block_isbad && 
+                      master->block_isbad(master, offset)) {
+                       offset += master->erasesize;
+                       if (offset == master->size)
+                               goto nogood;
+               }
+       }
        buf = vmalloc(master->erasesize);
 
        if (!buf)
                return -ENOMEM;
 
-       if ( directory < 0 )
-               offset = master->size + directory*master->erasesize;
-       else
-               offset = directory*master->erasesize;
-
        printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
               master->name, offset);
 
index 023653977a1ad762ecf1bc371d6b68fc328211fe..6ac81e35355cd39fc8232698b790de75f077e59b 100644 (file)
  */
 
 /*
- * This file includes UBI initialization and building of UBI devices. At the
- * moment UBI devices may only be added while UBI is initialized, but dynamic
- * device add/remove functionality is planned. Also, at the moment we only
- * attach UBI devices by scanning, which will become a bottleneck when flashes
- * reach certain large size. Then one may improve UBI and add other methods.
+ * This file includes UBI initialization and building of UBI devices.
+ *
+ * When UBI is initialized, it attaches all the MTD devices specified as the
+ * module load parameters or the kernel boot parameters. If MTD devices were
+ * specified, UBI does not attach any MTD device, but it is possible to do
+ * later using the "UBI control device".
+ *
+ * At the moment we only attach UBI devices by scanning, which will become a
+ * bottleneck when flashes reach certain large size. Then one may improve UBI
+ * and add other methods, although it does not seem to be easy to do.
  */
 
 #include <linux/err.h>
@@ -33,7 +38,9 @@
 #include <linux/moduleparam.h>
 #include <linux/stringify.h>
 #include <linux/stat.h>
+#include <linux/miscdevice.h>
 #include <linux/log2.h>
+#include <linux/kthread.h>
 #include "ubi.h"
 
 /* Maximum length of the 'mtd=' parameter */
  * struct mtd_dev_param - MTD device parameter description data structure.
  * @name: MTD device name or number string
  * @vid_hdr_offs: VID header offset
- * @data_offs: data offset
  */
 struct mtd_dev_param
 {
        char name[MTD_PARAM_LEN_MAX];
        int vid_hdr_offs;
-       int data_offs;
 };
 
 /* Numbers of elements set in the @mtd_dev_param array */
@@ -58,14 +63,27 @@ static int mtd_devs = 0;
 /* MTD devices specification parameters */
 static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
 
-/* Number of UBI devices in system */
-int ubi_devices_cnt;
+/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
+struct class *ubi_class;
+
+/* Slab cache for wear-leveling entries */
+struct kmem_cache *ubi_wl_entry_slab;
+
+/* UBI control character device */
+static struct miscdevice ubi_ctrl_cdev = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "ubi_ctrl",
+       .fops = &ubi_ctrl_cdev_operations,
+};
 
 /* All UBI devices in system */
-struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
+static struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
 
-/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
-struct class *ubi_class;
+/* Serializes UBI devices creations and removals */
+DEFINE_MUTEX(ubi_devices_mutex);
+
+/* Protects @ubi_devices and @ubi->ref_count */
+static DEFINE_SPINLOCK(ubi_devices_lock);
 
 /* "Show" method for files in '/<sysfs>/class/ubi/' */
 static ssize_t ubi_version_show(struct class *class, char *buf)
@@ -101,38 +119,150 @@ static struct device_attribute dev_min_io_size =
        __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL);
 static struct device_attribute dev_bgt_enabled =
        __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_mtd_num =
+       __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
+
+/**
+ * ubi_get_device - get UBI device.
+ * @ubi_num: UBI device number
+ *
+ * This function returns UBI device description object for UBI device number
+ * @ubi_num, or %NULL if the device does not exist. This function increases the
+ * device reference count to prevent removal of the device. In other words, the
+ * device cannot be removed if its reference count is not zero.
+ */
+struct ubi_device *ubi_get_device(int ubi_num)
+{
+       struct ubi_device *ubi;
+
+       spin_lock(&ubi_devices_lock);
+       ubi = ubi_devices[ubi_num];
+       if (ubi) {
+               ubi_assert(ubi->ref_count >= 0);
+               ubi->ref_count += 1;
+               get_device(&ubi->dev);
+       }
+       spin_unlock(&ubi_devices_lock);
+
+       return ubi;
+}
+
+/**
+ * ubi_put_device - drop an UBI device reference.
+ * @ubi: UBI device description object
+ */
+void ubi_put_device(struct ubi_device *ubi)
+{
+       spin_lock(&ubi_devices_lock);
+       ubi->ref_count -= 1;
+       put_device(&ubi->dev);
+       spin_unlock(&ubi_devices_lock);
+}
+
+/**
+ * ubi_get_by_major - get UBI device description object by character device
+ *                    major number.
+ * @major: major number
+ *
+ * This function is similar to 'ubi_get_device()', but it searches the device
+ * by its major number.
+ */
+struct ubi_device *ubi_get_by_major(int major)
+{
+       int i;
+       struct ubi_device *ubi;
+
+       spin_lock(&ubi_devices_lock);
+       for (i = 0; i < UBI_MAX_DEVICES; i++) {
+               ubi = ubi_devices[i];
+               if (ubi && MAJOR(ubi->cdev.dev) == major) {
+                       ubi_assert(ubi->ref_count >= 0);
+                       ubi->ref_count += 1;
+                       get_device(&ubi->dev);
+                       spin_unlock(&ubi_devices_lock);
+                       return ubi;
+               }
+       }
+       spin_unlock(&ubi_devices_lock);
+
+       return NULL;
+}
+
+/**
+ * ubi_major2num - get UBI device number by character device major number.
+ * @major: major number
+ *
+ * This function searches UBI device number object by its major number. If UBI
+ * device was not found, this function returns -ENODEV, otherwise the UBI device
+ * number is returned.
+ */
+int ubi_major2num(int major)
+{
+       int i, ubi_num = -ENODEV;
+
+       spin_lock(&ubi_devices_lock);
+       for (i = 0; i < UBI_MAX_DEVICES; i++) {
+               struct ubi_device *ubi = ubi_devices[i];
+
+               if (ubi && MAJOR(ubi->cdev.dev) == major) {
+                       ubi_num = ubi->ubi_num;
+                       break;
+               }
+       }
+       spin_unlock(&ubi_devices_lock);
+
+       return ubi_num;
+}
 
 /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
 static ssize_t dev_attribute_show(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
-       const struct ubi_device *ubi;
+       ssize_t ret;
+       struct ubi_device *ubi;
 
+       /*
+        * The below code looks weird, but it actually makes sense. We get the
+        * UBI device reference from the contained 'struct ubi_device'. But it
+        * is unclear if the device was removed or not yet. Indeed, if the
+        * device was removed before we increased its reference count,
+        * 'ubi_get_device()' will return -ENODEV and we fail.
+        *
+        * Remember, 'struct ubi_device' is freed in the release function, so
+        * we still can use 'ubi->ubi_num'.
+        */
        ubi = container_of(dev, struct ubi_device, dev);
+       ubi = ubi_get_device(ubi->ubi_num);
+       if (!ubi)
+               return -ENODEV;
+
        if (attr == &dev_eraseblock_size)
-               return sprintf(buf, "%d\n", ubi->leb_size);
+               ret = sprintf(buf, "%d\n", ubi->leb_size);
        else if (attr == &dev_avail_eraseblocks)
-               return sprintf(buf, "%d\n", ubi->avail_pebs);
+               ret = sprintf(buf, "%d\n", ubi->avail_pebs);
        else if (attr == &dev_total_eraseblocks)
-               return sprintf(buf, "%d\n", ubi->good_peb_count);
+               ret = sprintf(buf, "%d\n", ubi->good_peb_count);
        else if (attr == &dev_volumes_count)
-               return sprintf(buf, "%d\n", ubi->vol_count);
+               ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT);
        else if (attr == &dev_max_ec)
-               return sprintf(buf, "%d\n", ubi->max_ec);
+               ret = sprintf(buf, "%d\n", ubi->max_ec);
        else if (attr == &dev_reserved_for_bad)
-               return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
+               ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
        else if (attr == &dev_bad_peb_count)
-               return sprintf(buf, "%d\n", ubi->bad_peb_count);
+               ret = sprintf(buf, "%d\n", ubi->bad_peb_count);
        else if (attr == &dev_max_vol_count)
-               return sprintf(buf, "%d\n", ubi->vtbl_slots);
+               ret = sprintf(buf, "%d\n", ubi->vtbl_slots);
        else if (attr == &dev_min_io_size)
-               return sprintf(buf, "%d\n", ubi->min_io_size);
+               ret = sprintf(buf, "%d\n", ubi->min_io_size);
        else if (attr == &dev_bgt_enabled)
-               return sprintf(buf, "%d\n", ubi->thread_enabled);
+               ret = sprintf(buf, "%d\n", ubi->thread_enabled);
+       else if (attr == &dev_mtd_num)
+               ret = sprintf(buf, "%d\n", ubi->mtd->index);
        else
-               BUG();
+               ret = -EINVAL;
 
-       return 0;
+       ubi_put_device(ubi);
+       return ret;
 }
 
 /* Fake "release" method for UBI devices */
@@ -150,68 +280,44 @@ static int ubi_sysfs_init(struct ubi_device *ubi)
        int err;
 
        ubi->dev.release = dev_release;
-       ubi->dev.devt = MKDEV(ubi->major, 0);
+       ubi->dev.devt = ubi->cdev.dev;
        ubi->dev.class = ubi_class;
        sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num);
        err = device_register(&ubi->dev);
        if (err)
-               goto out;
+               return err;
 
        err = device_create_file(&ubi->dev, &dev_eraseblock_size);
        if (err)
-               goto out_unregister;
+               return err;
        err = device_create_file(&ubi->dev, &dev_avail_eraseblocks);
        if (err)
-               goto out_eraseblock_size;
+               return err;
        err = device_create_file(&ubi->dev, &dev_total_eraseblocks);
        if (err)
-               goto out_avail_eraseblocks;
+               return err;
        err = device_create_file(&ubi->dev, &dev_volumes_count);
        if (err)
-               goto out_total_eraseblocks;
+               return err;
        err = device_create_file(&ubi->dev, &dev_max_ec);
        if (err)
-               goto out_volumes_count;
+               return err;
        err = device_create_file(&ubi->dev, &dev_reserved_for_bad);
        if (err)
-               goto out_volumes_max_ec;
+               return err;
        err = device_create_file(&ubi->dev, &dev_bad_peb_count);
        if (err)
-               goto out_reserved_for_bad;
+               return err;
        err = device_create_file(&ubi->dev, &dev_max_vol_count);
        if (err)
-               goto out_bad_peb_count;
+               return err;
        err = device_create_file(&ubi->dev, &dev_min_io_size);
        if (err)
-               goto out_max_vol_count;
+               return err;
        err = device_create_file(&ubi->dev, &dev_bgt_enabled);
        if (err)
-               goto out_min_io_size;
-
-       return 0;
-
-out_min_io_size:
-       device_remove_file(&ubi->dev, &dev_min_io_size);
-out_max_vol_count:
-       device_remove_file(&ubi->dev, &dev_max_vol_count);
-out_bad_peb_count:
-       device_remove_file(&ubi->dev, &dev_bad_peb_count);
-out_reserved_for_bad:
-       device_remove_file(&ubi->dev, &dev_reserved_for_bad);
-out_volumes_max_ec:
-       device_remove_file(&ubi->dev, &dev_max_ec);
-out_volumes_count:
-       device_remove_file(&ubi->dev, &dev_volumes_count);
-out_total_eraseblocks:
-       device_remove_file(&ubi->dev, &dev_total_eraseblocks);
-out_avail_eraseblocks:
-       device_remove_file(&ubi->dev, &dev_avail_eraseblocks);
-out_eraseblock_size:
-       device_remove_file(&ubi->dev, &dev_eraseblock_size);
-out_unregister:
-       device_unregister(&ubi->dev);
-out:
-       ubi_err("failed to initialize sysfs for %s", ubi->ubi_name);
+               return err;
+       err = device_create_file(&ubi->dev, &dev_mtd_num);
        return err;
 }
 
@@ -221,6 +327,7 @@ out:
  */
 static void ubi_sysfs_close(struct ubi_device *ubi)
 {
+       device_remove_file(&ubi->dev, &dev_mtd_num);
        device_remove_file(&ubi->dev, &dev_bgt_enabled);
        device_remove_file(&ubi->dev, &dev_min_io_size);
        device_remove_file(&ubi->dev, &dev_max_vol_count);
@@ -244,7 +351,7 @@ static void kill_volumes(struct ubi_device *ubi)
 
        for (i = 0; i < ubi->vtbl_slots; i++)
                if (ubi->volumes[i])
-                       ubi_free_volume(ubi, i);
+                       ubi_free_volume(ubi, ubi->volumes[i]);
 }
 
 /**
@@ -259,9 +366,6 @@ static int uif_init(struct ubi_device *ubi)
        int i, err;
        dev_t dev;
 
-       mutex_init(&ubi->vtbl_mutex);
-       spin_lock_init(&ubi->volumes_lock);
-
        sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
 
        /*
@@ -278,39 +382,40 @@ static int uif_init(struct ubi_device *ubi)
                return err;
        }
 
+       ubi_assert(MINOR(dev) == 0);
        cdev_init(&ubi->cdev, &ubi_cdev_operations);
-       ubi->major = MAJOR(dev);
-       dbg_msg("%s major is %u", ubi->ubi_name, ubi->major);
+       dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev));
        ubi->cdev.owner = THIS_MODULE;
 
-       dev = MKDEV(ubi->major, 0);
        err = cdev_add(&ubi->cdev, dev, 1);
        if (err) {
-               ubi_err("cannot add character device %s", ubi->ubi_name);
+               ubi_err("cannot add character device");
                goto out_unreg;
        }
 
        err = ubi_sysfs_init(ubi);
        if (err)
-               goto out_cdev;
+               goto out_sysfs;
 
        for (i = 0; i < ubi->vtbl_slots; i++)
                if (ubi->volumes[i]) {
-                       err = ubi_add_volume(ubi, i);
-                       if (err)
+                       err = ubi_add_volume(ubi, ubi->volumes[i]);
+                       if (err) {
+                               ubi_err("cannot add volume %d", i);
                                goto out_volumes;
+                       }
                }
 
        return 0;
 
 out_volumes:
        kill_volumes(ubi);
+out_sysfs:
        ubi_sysfs_close(ubi);
-out_cdev:
        cdev_del(&ubi->cdev);
 out_unreg:
-       unregister_chrdev_region(MKDEV(ubi->major, 0),
-                                ubi->vtbl_slots + 1);
+       unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
+       ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err);
        return err;
 }
 
@@ -323,7 +428,7 @@ static void uif_close(struct ubi_device *ubi)
        kill_volumes(ubi);
        ubi_sysfs_close(ubi);
        cdev_del(&ubi->cdev);
-       unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1);
+       unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
 }
 
 /**
@@ -384,9 +489,9 @@ out_si:
  * assumed:
  *   o EC header is always at offset zero - this cannot be changed;
  *   o VID header starts just after the EC header at the closest address
- *   aligned to @io->@hdrs_min_io_size;
+ *     aligned to @io->hdrs_min_io_size;
  *   o data starts just after the VID header at the closest address aligned to
- *     @io->@min_io_size
+ *     @io->min_io_size
  *
  * This function returns zero in case of success and a negative error code in
  * case of failure.
@@ -407,6 +512,9 @@ static int io_init(struct ubi_device *ubi)
                return -EINVAL;
        }
 
+       if (ubi->vid_hdr_offset < 0)
+               return -EINVAL;
+
        /*
         * Note, in this implementation we support MTD devices with 0x7FFFFFFF
         * physical eraseblocks maximum.
@@ -424,7 +532,8 @@ static int io_init(struct ubi_device *ubi)
 
        /* Make sure minimal I/O unit is power of 2 */
        if (!is_power_of_2(ubi->min_io_size)) {
-               ubi_err("bad min. I/O unit");
+               ubi_err("min. I/O unit (%d) is not power of 2",
+                       ubi->min_io_size);
                return -EINVAL;
        }
 
@@ -453,10 +562,8 @@ static int io_init(struct ubi_device *ubi)
        }
 
        /* Similar for the data offset */
-       if (ubi->leb_start == 0) {
-               ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize;
-               ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
-       }
+       ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE;
+       ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
 
        dbg_msg("vid_hdr_offset   %d", ubi->vid_hdr_offset);
        dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset);
@@ -514,76 +621,147 @@ static int io_init(struct ubi_device *ubi)
 }
 
 /**
- * attach_mtd_dev - attach an MTD device.
- * @mtd_dev: MTD device name or number string
- * @vid_hdr_offset: VID header offset
- * @data_offset: data offset
+ * autoresize - re-size the volume which has the "auto-resize" flag set.
+ * @ubi: UBI device description object
+ * @vol_id: ID of the volume to re-size
  *
- * This function attaches an MTD device to UBI. It first treats @mtd_dev as the
- * MTD device name, and tries to open it by this name. If it is unable to open,
- * it tries to convert @mtd_dev to an integer and open the MTD device by its
- * number. Returns zero in case of success and a negative error code in case of
- * failure.
+ * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in
+ * the volume table to the largest possible size. See comments in ubi-header.h
+ * for more description of the flag. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
-static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
-                         int data_offset)
+static int autoresize(struct ubi_device *ubi, int vol_id)
 {
-       struct ubi_device *ubi;
-       struct mtd_info *mtd;
-       int i, err;
+       struct ubi_volume_desc desc;
+       struct ubi_volume *vol = ubi->volumes[vol_id];
+       int err, old_reserved_pebs = vol->reserved_pebs;
 
-       mtd = get_mtd_device_nm(mtd_dev);
-       if (IS_ERR(mtd)) {
-               int mtd_num;
-               char *endp;
+       /*
+        * Clear the auto-resize flag in the volume in-memory copy of the
+        * volume table, and 'ubi_resize_volume()' will propogate this change
+        * to the flash.
+        */
+       ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG;
 
-               if (PTR_ERR(mtd) != -ENODEV)
-                       return PTR_ERR(mtd);
+       if (ubi->avail_pebs == 0) {
+               struct ubi_vtbl_record vtbl_rec;
 
                /*
-                * Probably this is not MTD device name but MTD device number -
-                * check this out.
+                * No avalilable PEBs to re-size the volume, clear the flag on
+                * flash and exit.
                 */
-               mtd_num = simple_strtoul(mtd_dev, &endp, 0);
-               if (*endp != '\0' || mtd_dev == endp) {
-                       ubi_err("incorrect MTD device: \"%s\"", mtd_dev);
-                       return -ENODEV;
-               }
-
-               mtd = get_mtd_device(NULL, mtd_num);
-               if (IS_ERR(mtd))
-                       return PTR_ERR(mtd);
+               memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
+                      sizeof(struct ubi_vtbl_record));
+               err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+               if (err)
+                       ubi_err("cannot clean auto-resize flag for volume %d",
+                               vol_id);
+       } else {
+               desc.vol = vol;
+               err = ubi_resize_volume(&desc,
+                                       old_reserved_pebs + ubi->avail_pebs);
+               if (err)
+                       ubi_err("cannot auto-resize volume %d", vol_id);
        }
 
-       /* Check if we already have the same MTD device attached */
-       for (i = 0; i < ubi_devices_cnt; i++)
-               if (ubi_devices[i]->mtd->index == mtd->index) {
-                       ubi_err("mtd%d is already attached to ubi%d",
+       if (err)
+               return err;
+
+       ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id,
+               vol->name, old_reserved_pebs, vol->reserved_pebs);
+       return 0;
+}
+
+/**
+ * ubi_attach_mtd_dev - attach an MTD device.
+ * @mtd_dev: MTD device description object
+ * @ubi_num: number to assign to the new UBI device
+ * @vid_hdr_offset: VID header offset
+ *
+ * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number
+ * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
+ * which case this function finds a vacant device nubert and assings it
+ * automatically. Returns the new UBI device number in case of success and a
+ * negative error code in case of failure.
+ *
+ * Note, the invocations of this function has to be serialized by the
+ * @ubi_devices_mutex.
+ */
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
+{
+       struct ubi_device *ubi;
+       int i, err;
+
+       /*
+        * Check if we already have the same MTD device attached.
+        *
+        * Note, this function assumes that UBI devices creations and deletions
+        * are serialized, so it does not take the &ubi_devices_lock.
+        */
+       for (i = 0; i < UBI_MAX_DEVICES; i++) {
+               ubi = ubi_devices[i];
+               if (ubi && mtd->index == ubi->mtd->index) {
+                       dbg_err("mtd%d is already attached to ubi%d",
                                mtd->index, i);
-                       err = -EINVAL;
-                       goto out_mtd;
+                       return -EEXIST;
                }
+       }
 
-       ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device),
-                                                    GFP_KERNEL);
-       if (!ubi) {
-               err = -ENOMEM;
-               goto out_mtd;
+       /*
+        * Make sure this MTD device is not emulated on top of an UBI volume
+        * already. Well, generally this recursion works fine, but there are
+        * different problems like the UBI module takes a reference to itself
+        * by attaching (and thus, opening) the emulated MTD device. This
+        * results in inability to unload the module. And in general it makes
+        * no sense to attach emulated MTD devices, so we prohibit this.
+        */
+       if (mtd->type == MTD_UBIVOLUME) {
+               ubi_err("refuse attaching mtd%d - it is already emulated on "
+                       "top of UBI", mtd->index);
+               return -EINVAL;
        }
 
-       ubi->ubi_num = ubi_devices_cnt;
-       ubi->mtd = mtd;
+       if (ubi_num == UBI_DEV_NUM_AUTO) {
+               /* Search for an empty slot in the @ubi_devices array */
+               for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
+                       if (!ubi_devices[ubi_num])
+                               break;
+               if (ubi_num == UBI_MAX_DEVICES) {
+                       dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES);
+                       return -ENFILE;
+               }
+       } else {
+               if (ubi_num >= UBI_MAX_DEVICES)
+                       return -EINVAL;
+
+               /* Make sure ubi_num is not busy */
+               if (ubi_devices[ubi_num]) {
+                       dbg_err("ubi%d already exists", ubi_num);
+                       return -EEXIST;
+               }
+       }
 
-       dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d",
-               ubi->mtd->index, ubi_devices_cnt, vid_hdr_offset, data_offset);
+       ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);
+       if (!ubi)
+               return -ENOMEM;
 
+       ubi->mtd = mtd;
+       ubi->ubi_num = ubi_num;
        ubi->vid_hdr_offset = vid_hdr_offset;
-       ubi->leb_start = data_offset;
+       ubi->autoresize_vol_id = -1;
+
+       mutex_init(&ubi->buf_mutex);
+       mutex_init(&ubi->ckvol_mutex);
+       mutex_init(&ubi->volumes_mutex);
+       spin_lock_init(&ubi->volumes_lock);
+
+       dbg_msg("attaching mtd%d to ubi%d: VID header offset %d",
+               mtd->index, ubi_num, vid_hdr_offset);
+
        err = io_init(ubi);
        if (err)
                goto out_free;
 
-       mutex_init(&ubi->buf_mutex);
        ubi->peb_buf1 = vmalloc(ubi->peb_size);
        if (!ubi->peb_buf1)
                goto out_free;
@@ -605,12 +783,26 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
                goto out_free;
        }
 
+       if (ubi->autoresize_vol_id != -1) {
+               err = autoresize(ubi, ubi->autoresize_vol_id);
+               if (err)
+                       goto out_detach;
+       }
+
        err = uif_init(ubi);
        if (err)
                goto out_detach;
 
-       ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
-       ubi_msg("MTD device name:            \"%s\"", ubi->mtd->name);
+       ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
+       if (IS_ERR(ubi->bgt_thread)) {
+               err = PTR_ERR(ubi->bgt_thread);
+               ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
+                       err);
+               goto out_uif;
+       }
+
+       ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
+       ubi_msg("MTD device name:            \"%s\"", mtd->name);
        ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
        ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
                ubi->peb_size, ubi->peb_size >> 10);
@@ -638,9 +830,11 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
                wake_up_process(ubi->bgt_thread);
        }
 
-       ubi_devices_cnt += 1;
-       return 0;
+       ubi_devices[ubi_num] = ubi;
+       return ubi_num;
 
+out_uif:
+       uif_close(ubi);
 out_detach:
        ubi_eba_close(ubi);
        ubi_wl_close(ubi);
@@ -652,21 +846,58 @@ out_free:
        vfree(ubi->dbg_peb_buf);
 #endif
        kfree(ubi);
-out_mtd:
-       put_mtd_device(mtd);
-       ubi_devices[ubi_devices_cnt] = NULL;
        return err;
 }
 
 /**
- * detach_mtd_dev - detach an MTD device.
- * @ubi: UBI device description object
+ * ubi_detach_mtd_dev - detach an MTD device.
+ * @ubi_num: UBI device number to detach from
+ * @anyway: detach MTD even if device reference count is not zero
+ *
+ * This function destroys an UBI device number @ubi_num and detaches the
+ * underlying MTD device. Returns zero in case of success and %-EBUSY if the
+ * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not
+ * exist.
+ *
+ * Note, the invocations of this function has to be serialized by the
+ * @ubi_devices_mutex.
  */
-static void detach_mtd_dev(struct ubi_device *ubi)
+int ubi_detach_mtd_dev(int ubi_num, int anyway)
 {
-       int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index;
+       struct ubi_device *ubi;
+
+       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+               return -EINVAL;
+
+       spin_lock(&ubi_devices_lock);
+       ubi = ubi_devices[ubi_num];
+       if (!ubi) {
+               spin_unlock(&ubi_devices_lock);
+               return -EINVAL;
+       }
+
+       if (ubi->ref_count) {
+               if (!anyway) {
+                       spin_unlock(&ubi_devices_lock);
+                       return -EBUSY;
+               }
+               /* This may only happen if there is a bug */
+               ubi_err("%s reference count %d, destroy anyway",
+                       ubi->ubi_name, ubi->ref_count);
+       }
+       ubi_devices[ubi_num] = NULL;
+       spin_unlock(&ubi_devices_lock);
 
+       ubi_assert(ubi_num == ubi->ubi_num);
        dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
+
+       /*
+        * Before freeing anything, we have to stop the background thread to
+        * prevent it from doing anything on this device while we are freeing.
+        */
+       if (ubi->bgt_thread)
+               kthread_stop(ubi->bgt_thread);
+
        uif_close(ubi);
        ubi_eba_close(ubi);
        ubi_wl_close(ubi);
@@ -677,11 +908,37 @@ static void detach_mtd_dev(struct ubi_device *ubi)
 #ifdef CONFIG_MTD_UBI_DEBUG
        vfree(ubi->dbg_peb_buf);
 #endif
-       kfree(ubi_devices[ubi_num]);
-       ubi_devices[ubi_num] = NULL;
-       ubi_devices_cnt -= 1;
-       ubi_assert(ubi_devices_cnt >= 0);
-       ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num);
+       ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
+       kfree(ubi);
+       return 0;
+}
+
+/**
+ * find_mtd_device - open an MTD device by its name or number.
+ * @mtd_dev: name or number of the device
+ *
+ * This function tries to open and MTD device described by @mtd_dev string,
+ * which is first treated as an ASCII number, and if it is not true, it is
+ * treated as MTD device name. Returns MTD device description object in case of
+ * success and a negative error code in case of failure.
+ */
+static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
+{
+       struct mtd_info *mtd;
+       int mtd_num;
+       char *endp;
+
+       mtd_num = simple_strtoul(mtd_dev, &endp, 0);
+       if (*endp != '\0' || mtd_dev == endp) {
+               /*
+                * This does not look like an ASCII integer, probably this is
+                * MTD device name.
+                */
+               mtd = get_mtd_device_nm(mtd_dev);
+       } else
+               mtd = get_mtd_device(NULL, mtd_num);
+
+       return mtd;
 }
 
 static int __init ubi_init(void)
@@ -693,47 +950,96 @@ static int __init ubi_init(void)
        BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
 
        if (mtd_devs > UBI_MAX_DEVICES) {
-               printk("UBI error: too many MTD devices, maximum is %d\n",
-                      UBI_MAX_DEVICES);
+               printk(KERN_ERR "UBI error: too many MTD devices, "
+                      "maximum is %d\n", UBI_MAX_DEVICES);
                return -EINVAL;
        }
 
+       /* Create base sysfs directory and sysfs files */
        ubi_class = class_create(THIS_MODULE, UBI_NAME_STR);
-       if (IS_ERR(ubi_class))
-               return PTR_ERR(ubi_class);
+       if (IS_ERR(ubi_class)) {
+               err = PTR_ERR(ubi_class);
+               printk(KERN_ERR "UBI error: cannot create UBI class\n");
+               goto out;
+       }
 
        err = class_create_file(ubi_class, &ubi_version);
-       if (err)
+       if (err) {
+               printk(KERN_ERR "UBI error: cannot create sysfs file\n");
                goto out_class;
+       }
+
+       err = misc_register(&ubi_ctrl_cdev);
+       if (err) {
+               printk(KERN_ERR "UBI error: cannot register device\n");
+               goto out_version;
+       }
+
+       ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
+                                               sizeof(struct ubi_wl_entry),
+                                               0, 0, NULL);
+       if (!ubi_wl_entry_slab)
+               goto out_dev_unreg;
 
        /* Attach MTD devices */
        for (i = 0; i < mtd_devs; i++) {
                struct mtd_dev_param *p = &mtd_dev_param[i];
+               struct mtd_info *mtd;
 
                cond_resched();
-               err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
-               if (err)
+
+               mtd = open_mtd_device(p->name);
+               if (IS_ERR(mtd)) {
+                       err = PTR_ERR(mtd);
+                       goto out_detach;
+               }
+
+               mutex_lock(&ubi_devices_mutex);
+               err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO,
+                                        p->vid_hdr_offs);
+               mutex_unlock(&ubi_devices_mutex);
+               if (err < 0) {
+                       put_mtd_device(mtd);
+                       printk(KERN_ERR "UBI error: cannot attach %s\n",
+                              p->name);
                        goto out_detach;
+               }
        }
 
        return 0;
 
 out_detach:
        for (k = 0; k < i; k++)
-               detach_mtd_dev(ubi_devices[k]);
+               if (ubi_devices[k]) {
+                       mutex_lock(&ubi_devices_mutex);
+                       ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
+                       mutex_unlock(&ubi_devices_mutex);
+               }
+       kmem_cache_destroy(ubi_wl_entry_slab);
+out_dev_unreg:
+       misc_deregister(&ubi_ctrl_cdev);
+out_version:
        class_remove_file(ubi_class, &ubi_version);
 out_class:
        class_destroy(ubi_class);
+out:
+       printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err);
        return err;
 }
 module_init(ubi_init);
 
 static void __exit ubi_exit(void)
 {
-       int i, n = ubi_devices_cnt;
+       int i;
 
-       for (i = 0; i < n; i++)
-               detach_mtd_dev(ubi_devices[i]);
+       for (i = 0; i < UBI_MAX_DEVICES; i++)
+               if (ubi_devices[i]) {
+                       mutex_lock(&ubi_devices_mutex);
+                       ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
+                       mutex_unlock(&ubi_devices_mutex);
+               }
+       kmem_cache_destroy(ubi_wl_entry_slab);
+       misc_deregister(&ubi_ctrl_cdev);
        class_remove_file(ubi_class, &ubi_version);
        class_destroy(ubi_class);
 }
@@ -754,7 +1060,8 @@ static int __init bytes_str_to_int(const char *str)
 
        result = simple_strtoul(str, &endp, 0);
        if (str == endp || result < 0) {
-               printk("UBI error: incorrect bytes count: \"%s\"\n", str);
+               printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n",
+                      str);
                return -EINVAL;
        }
 
@@ -764,15 +1071,14 @@ static int __init bytes_str_to_int(const char *str)
        case 'M':
                result *= 1024;
        case 'K':
-       case 'k':
                result *= 1024;
-               if (endp[1] == 'i' && (endp[2] == '\0' ||
-                         endp[2] == 'B'  || endp[2] == 'b'))
+               if (endp[1] == 'i' && endp[2] == 'B')
                        endp += 2;
        case '\0':
                break;
        default:
-               printk("UBI error: incorrect bytes count: \"%s\"\n", str);
+               printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n",
+                      str);
                return -EINVAL;
        }
 
@@ -793,23 +1099,27 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
        struct mtd_dev_param *p;
        char buf[MTD_PARAM_LEN_MAX];
        char *pbuf = &buf[0];
-       char *tokens[3] = {NULL, NULL, NULL};
+       char *tokens[2] = {NULL, NULL};
+
+       if (!val)
+               return -EINVAL;
 
        if (mtd_devs == UBI_MAX_DEVICES) {
-               printk("UBI error: too many parameters, max. is %d\n",
+               printk(KERN_ERR "UBI error: too many parameters, max. is %d\n",
                       UBI_MAX_DEVICES);
                return -EINVAL;
        }
 
        len = strnlen(val, MTD_PARAM_LEN_MAX);
        if (len == MTD_PARAM_LEN_MAX) {
-               printk("UBI error: parameter \"%s\" is too long, max. is %d\n",
-                      val, MTD_PARAM_LEN_MAX);
+               printk(KERN_ERR "UBI error: parameter \"%s\" is too long, "
+                      "max. is %d\n", val, MTD_PARAM_LEN_MAX);
                return -EINVAL;
        }
 
        if (len == 0) {
-               printk("UBI warning: empty 'mtd=' parameter - ignored\n");
+               printk(KERN_WARNING "UBI warning: empty 'mtd=' parameter - "
+                      "ignored\n");
                return 0;
        }
 
@@ -819,11 +1129,12 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
        if (buf[len - 1] == '\n')
                buf[len - 1] = '\0';
 
-       for (i = 0; i < 3; i++)
+       for (i = 0; i < 2; i++)
                tokens[i] = strsep(&pbuf, ",");
 
        if (pbuf) {
-               printk("UBI error: too many arguments at \"%s\"\n", val);
+               printk(KERN_ERR "UBI error: too many arguments at \"%s\"\n",
+                      val);
                return -EINVAL;
        }
 
@@ -832,13 +1143,9 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
 
        if (tokens[1])
                p->vid_hdr_offs = bytes_str_to_int(tokens[1]);
-       if (tokens[2])
-               p->data_offs = bytes_str_to_int(tokens[2]);
 
        if (p->vid_hdr_offs < 0)
                return p->vid_hdr_offs;
-       if (p->data_offs < 0)
-               return p->data_offs;
 
        mtd_devs += 1;
        return 0;
@@ -846,16 +1153,15 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
 
 module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000);
 MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: "
-                     "mtd=<name|num>[,<vid_hdr_offs>,<data_offs>]. "
+                     "mtd=<name|num>[,<vid_hdr_offs>].\n"
                      "Multiple \"mtd\" parameters may be specified.\n"
-                     "MTD devices may be specified by their number or name. "
-                     "Optional \"vid_hdr_offs\" and \"data_offs\" parameters "
-                     "specify UBI VID header position and data starting "
-                     "position to be used by UBI.\n"
-                     "Example: mtd=content,1984,2048 mtd=4 - attach MTD device"
-                     "with name content using VID header offset 1984 and data "
-                     "start 2048, and MTD device number 4 using default "
-                     "offsets");
+                     "MTD devices may be specified by their number or name.\n"
+                     "Optional \"vid_hdr_offs\" parameter specifies UBI VID "
+                     "header position and data starting position to be used "
+                     "by UBI.\n"
+                     "Example: mtd=content,1984 mtd=4 - attach MTD device"
+                     "with name \"content\" using VID header offset 1984, and "
+                     "MTD device number 4 with default VID header offset.");
 
 MODULE_VERSION(__stringify(UBI_VERSION));
 MODULE_DESCRIPTION("UBI - Unsorted Block Images");
index fe4da1e96c52a67b1b79676ff281e1e4f6162b8b..9d6aae5449b67010e0ba80e247aab81e3b030ce9 100644 (file)
  *
  * Major and minor numbers are assigned dynamically to both UBI and volume
  * character devices.
+ *
+ * Well, there is the third kind of character devices - the UBI control
+ * character device, which allows to manipulate by UBI devices - create and
+ * delete them. In other words, it is used for attaching and detaching MTD
+ * devices.
  */
 
 #include <linux/module.h>
 #include <asm/div64.h>
 #include "ubi.h"
 
-/*
- * Maximum sequence numbers of UBI and volume character device IOCTLs (direct
- * logical eraseblock erase is a debug-only feature).
- */
-#define UBI_CDEV_IOC_MAX_SEQ 2
-#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
-#define VOL_CDEV_IOC_MAX_SEQ 1
-#else
-#define VOL_CDEV_IOC_MAX_SEQ 2
-#endif
-
-/**
- * major_to_device - get UBI device object by character device major number.
- * @major: major number
- *
- * This function returns a pointer to the UBI device object.
- */
-static struct ubi_device *major_to_device(int major)
-{
-       int i;
-
-       for (i = 0; i < ubi_devices_cnt; i++)
-               if (ubi_devices[i] && ubi_devices[i]->major == major)
-                       return ubi_devices[i];
-       BUG();
-       return NULL;
-}
-
 /**
  * get_exclusive - get exclusive access to an UBI volume.
  * @desc: volume descriptor
@@ -124,9 +101,11 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
 static int vol_cdev_open(struct inode *inode, struct file *file)
 {
        struct ubi_volume_desc *desc;
-       const struct ubi_device *ubi = major_to_device(imajor(inode));
-       int vol_id = iminor(inode) - 1;
-       int mode;
+       int vol_id = iminor(inode) - 1, mode, ubi_num;
+
+       ubi_num = ubi_major2num(imajor(inode));
+       if (ubi_num < 0)
+               return ubi_num;
 
        if (file->f_mode & FMODE_WRITE)
                mode = UBI_READWRITE;
@@ -135,7 +114,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
 
        dbg_msg("open volume %d, mode %d", vol_id, mode);
 
-       desc = ubi_open_volume(ubi->ubi_num, vol_id, mode);
+       desc = ubi_open_volume(ubi_num, vol_id, mode);
        if (IS_ERR(desc))
                return PTR_ERR(desc);
 
@@ -153,8 +132,15 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
        if (vol->updating) {
                ubi_warn("update of volume %d not finished, volume is damaged",
                         vol->vol_id);
+               ubi_assert(!vol->changing_leb);
                vol->updating = 0;
                vfree(vol->upd_buf);
+       } else if (vol->changing_leb) {
+               dbg_msg("only %lld of %lld bytes received for atomic LEB change"
+                       " for volume %d:%d, cancel", vol->upd_received,
+                       vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id);
+               vol->changing_leb = 0;
+               vfree(vol->upd_buf);
        }
 
        ubi_close_volume(desc);
@@ -205,13 +191,13 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
        struct ubi_volume_desc *desc = file->private_data;
        struct ubi_volume *vol = desc->vol;
        struct ubi_device *ubi = vol->ubi;
-       int err, lnum, off, len,  vol_id = desc->vol->vol_id, tbuf_size;
+       int err, lnum, off, len,  tbuf_size;
        size_t count_save = count;
        void *tbuf;
        uint64_t tmp;
 
        dbg_msg("read %zd bytes from offset %lld of volume %d",
-               count, *offp, vol_id);
+               count, *offp, vol->vol_id);
 
        if (vol->updating) {
                dbg_err("updating");
@@ -225,7 +211,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
                return 0;
 
        if (vol->corrupted)
-               dbg_msg("read from corrupted volume %d", vol_id);
+               dbg_msg("read from corrupted volume %d", vol->vol_id);
 
        if (*offp + count > vol->used_bytes)
                count_save = count = vol->used_bytes - *offp;
@@ -249,7 +235,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
                if (off + len >= vol->usable_leb_size)
                        len = vol->usable_leb_size - off;
 
-               err = ubi_eba_read_leb(ubi, vol_id, lnum, tbuf, off, len, 0);
+               err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0);
                if (err)
                        break;
 
@@ -289,13 +275,13 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
        struct ubi_volume_desc *desc = file->private_data;
        struct ubi_volume *vol = desc->vol;
        struct ubi_device *ubi = vol->ubi;
-       int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0;
+       int lnum, off, len, tbuf_size, err = 0;
        size_t count_save = count;
        char *tbuf;
        uint64_t tmp;
 
        dbg_msg("requested: write %zd bytes to offset %lld of volume %u",
-               count, *offp, desc->vol->vol_id);
+               count, *offp, vol->vol_id);
 
        if (vol->vol_type == UBI_STATIC_VOLUME)
                return -EROFS;
@@ -339,7 +325,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
                        break;
                }
 
-               err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len,
+               err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len,
                                        UBI_UNKNOWN);
                if (err)
                        break;
@@ -372,22 +358,32 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
        struct ubi_volume *vol = desc->vol;
        struct ubi_device *ubi = vol->ubi;
 
-       if (!vol->updating)
+       if (!vol->updating && !vol->changing_leb)
                return vol_cdev_direct_write(file, buf, count, offp);
 
-       err = ubi_more_update_data(ubi, vol->vol_id, buf, count);
+       if (vol->updating)
+               err = ubi_more_update_data(ubi, vol, buf, count);
+       else
+               err = ubi_more_leb_change_data(ubi, vol, buf, count);
+
        if (err < 0) {
-               ubi_err("cannot write %zd bytes of update data", count);
+               ubi_err("cannot accept more %zd bytes of data, error %d",
+                       count, err);
                return err;
        }
 
        if (err) {
                /*
-                * Update is finished, @err contains number of actually written
-                * bytes now.
+                * The operation is finished, @err contains number of actually
+                * written bytes.
                 */
                count = err;
 
+               if (vol->changing_leb) {
+                       revoke_exclusive(desc, UBI_READWRITE);
+                       return count;
+               }
+
                err = ubi_check_volume(ubi, vol->vol_id);
                if (err < 0)
                        return err;
@@ -402,7 +398,6 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
                revoke_exclusive(desc, UBI_READWRITE);
        }
 
-       *offp += count;
        return count;
 }
 
@@ -447,11 +442,46 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
                if (err < 0)
                        break;
 
-               err = ubi_start_update(ubi, vol->vol_id, bytes);
+               err = ubi_start_update(ubi, vol, bytes);
                if (bytes == 0)
                        revoke_exclusive(desc, UBI_READWRITE);
+               break;
+       }
+
+       /* Atomic logical eraseblock change command */
+       case UBI_IOCEBCH:
+       {
+               struct ubi_leb_change_req req;
+
+               err = copy_from_user(&req, argp,
+                                    sizeof(struct ubi_leb_change_req));
+               if (err) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (desc->mode == UBI_READONLY ||
+                   vol->vol_type == UBI_STATIC_VOLUME) {
+                       err = -EROFS;
+                       break;
+               }
+
+               /* Validate the request */
+               err = -EINVAL;
+               if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
+                   req.bytes < 0 || req.lnum >= vol->usable_leb_size)
+                       break;
+               if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM &&
+                   req.dtype != UBI_UNKNOWN)
+                       break;
+
+               err = get_exclusive(desc);
+               if (err < 0)
+                       break;
 
-               file->f_pos = 0;
+               err = ubi_start_leb_change(ubi, vol, &req);
+               if (req.bytes == 0)
+                       revoke_exclusive(desc, UBI_READWRITE);
                break;
        }
 
@@ -467,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
                        break;
                }
 
-               if (desc->mode == UBI_READONLY) {
+               if (desc->mode == UBI_READONLY ||
+                   vol->vol_type == UBI_STATIC_VOLUME) {
                        err = -EROFS;
                        break;
                }
@@ -477,13 +508,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
                        break;
                }
 
-               if (vol->vol_type != UBI_DYNAMIC_VOLUME) {
-                       err = -EROFS;
-                       break;
-               }
-
                dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
-               err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum);
+               err = ubi_eba_unmap_leb(ubi, vol, lnum);
                if (err)
                        break;
 
@@ -580,9 +606,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
        if (!capable(CAP_SYS_RESOURCE))
                return -EPERM;
 
-       ubi = major_to_device(imajor(inode));
-       if (IS_ERR(ubi))
-               return PTR_ERR(ubi);
+       ubi = ubi_get_by_major(imajor(inode));
+       if (!ubi)
+               return -ENODEV;
 
        switch (cmd) {
        /* Create volume command */
@@ -591,8 +617,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                struct ubi_mkvol_req req;
 
                dbg_msg("create volume");
-               err = copy_from_user(&req, argp,
-                                      sizeof(struct ubi_mkvol_req));
+               err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req));
                if (err) {
                        err = -EFAULT;
                        break;
@@ -604,7 +629,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 
                req.name[req.name_len] = '\0';
 
+               mutex_lock(&ubi->volumes_mutex);
                err = ubi_create_volume(ubi, &req);
+               mutex_unlock(&ubi->volumes_mutex);
                if (err)
                        break;
 
@@ -633,10 +660,16 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                        break;
                }
 
+               mutex_lock(&ubi->volumes_mutex);
                err = ubi_remove_volume(desc);
-               if (err)
-                       ubi_close_volume(desc);
+               mutex_unlock(&ubi->volumes_mutex);
 
+               /*
+                * The volume is deleted (unless an error occurred), and the
+                * 'struct ubi_volume' object will be freed when
+                * 'ubi_close_volume()' will call 'put_device()'.
+                */
+               ubi_close_volume(desc);
                break;
        }
 
@@ -648,8 +681,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                struct ubi_rsvol_req req;
 
                dbg_msg("re-size volume");
-               err = copy_from_user(&req, argp,
-                                      sizeof(struct ubi_rsvol_req));
+               err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req));
                if (err) {
                        err = -EFAULT;
                        break;
@@ -669,7 +701,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                pebs = !!do_div(tmp, desc->vol->usable_leb_size);
                pebs += tmp;
 
+               mutex_lock(&ubi->volumes_mutex);
                err = ubi_resize_volume(desc, pebs);
+               mutex_unlock(&ubi->volumes_mutex);
                ubi_close_volume(desc);
                break;
        }
@@ -679,9 +713,93 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
+       ubi_put_device(ubi);
        return err;
 }
 
+static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
+                          unsigned int cmd, unsigned long arg)
+{
+       int err = 0;
+       void __user *argp = (void __user *)arg;
+
+       if (!capable(CAP_SYS_RESOURCE))
+               return -EPERM;
+
+       switch (cmd) {
+       /* Attach an MTD device command */
+       case UBI_IOCATT:
+       {
+               struct ubi_attach_req req;
+               struct mtd_info *mtd;
+
+               dbg_msg("attach MTD device");
+               err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req));
+               if (err) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (req.mtd_num < 0 ||
+                   (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               mtd = get_mtd_device(NULL, req.mtd_num);
+               if (IS_ERR(mtd)) {
+                       err = PTR_ERR(mtd);
+                       break;
+               }
+
+               /*
+                * Note, further request verification is done by
+                * 'ubi_attach_mtd_dev()'.
+                */
+               mutex_lock(&ubi_devices_mutex);
+               err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset);
+               mutex_unlock(&ubi_devices_mutex);
+               if (err < 0)
+                       put_mtd_device(mtd);
+               else
+                       /* @err contains UBI device number */
+                       err = put_user(err, (__user int32_t *)argp);
+
+               break;
+       }
+
+       /* Detach an MTD device command */
+       case UBI_IOCDET:
+       {
+               int ubi_num;
+
+               dbg_msg("dettach MTD device");
+               err = get_user(ubi_num, (__user int32_t *)argp);
+               if (err) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               mutex_lock(&ubi_devices_mutex);
+               err = ubi_detach_mtd_dev(ubi_num, 0);
+               mutex_unlock(&ubi_devices_mutex);
+               break;
+       }
+
+       default:
+               err = -ENOTTY;
+               break;
+       }
+
+       return err;
+}
+
+/* UBI control character device operations */
+struct file_operations ubi_ctrl_cdev_operations = {
+       .ioctl = ctrl_cdev_ioctl,
+       .owner = THIS_MODULE,
+};
+
 /* UBI character device operations */
 struct file_operations ubi_cdev_operations = {
        .owner = THIS_MODULE,
index 467722eb618b20a384320e4bee15be409f2f5e77..51c40b17f1ec5c967994666ad0f7f3ce4b689f39 100644 (file)
@@ -39,8 +39,9 @@
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG
 /* Generic debugging message */
-#define dbg_msg(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)                                    \
+       printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
+              current->pid, __FUNCTION__, ##__VA_ARGS__)
 
 #define ubi_dbg_dump_stack() dump_stack()
 
@@ -76,36 +77,28 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
 /* Messages from the eraseblock association unit */
-#define dbg_eba(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG eba: %s: " fmt "\n", __FUNCTION__, \
-              ##__VA_ARGS__)
+#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
 #else
 #define dbg_eba(fmt, ...) ({})
 #endif
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
 /* Messages from the wear-leveling unit */
-#define dbg_wl(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG wl: %s: " fmt "\n", __FUNCTION__, \
-              ##__VA_ARGS__)
+#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
 #else
 #define dbg_wl(fmt, ...) ({})
 #endif
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
 /* Messages from the input/output unit */
-#define dbg_io(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG io: %s: " fmt "\n", __FUNCTION__, \
-              ##__VA_ARGS__)
+#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
 #else
 #define dbg_io(fmt, ...) ({})
 #endif
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
 /* Initialization and build messages */
-#define dbg_bld(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG bld: %s: " fmt "\n", __FUNCTION__, \
-              ##__VA_ARGS__)
+#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
 #else
 #define dbg_bld(fmt, ...) ({})
 #endif
index 880fa369035296bbd85e5f8027249a78f59d42f3..7ce91ca742b136c7b60ac6db25ffb3d3771d2d6b 100644 (file)
@@ -31,7 +31,7 @@
  * logical eraseblock it is locked for reading or writing. The per-logical
  * eraseblock locking is implemented by means of the lock tree. The lock tree
  * is an RB-tree which refers all the currently locked logical eraseblocks. The
- * lock tree elements are &struct ltree_entry objects. They are indexed by
+ * lock tree elements are &struct ubi_ltree_entry objects. They are indexed by
  * (@vol_id, @lnum) pairs.
  *
  * EBA also maintains the global sequence counter which is incremented each
 /* Number of physical eraseblocks reserved for atomic LEB change operation */
 #define EBA_RESERVED_PEBS 1
 
-/**
- * struct ltree_entry - an entry in the lock tree.
- * @rb: links RB-tree nodes
- * @vol_id: volume ID of the locked logical eraseblock
- * @lnum: locked logical eraseblock number
- * @users: how many tasks are using this logical eraseblock or wait for it
- * @mutex: read/write mutex to implement read/write access serialization to
- * the (@vol_id, @lnum) logical eraseblock
- *
- * When a logical eraseblock is being locked - corresponding &struct ltree_entry
- * object is inserted to the lock tree (@ubi->ltree).
- */
-struct ltree_entry {
-       struct rb_node rb;
-       int vol_id;
-       int lnum;
-       int users;
-       struct rw_semaphore mutex;
-};
-
-/* Slab cache for lock-tree entries */
-static struct kmem_cache *ltree_slab;
-
 /**
  * next_sqnum - get next sequence number.
  * @ubi: UBI device description object
@@ -101,7 +78,7 @@ static unsigned long long next_sqnum(struct ubi_device *ubi)
  */
 static int ubi_get_compat(const struct ubi_device *ubi, int vol_id)
 {
-       if (vol_id == UBI_LAYOUT_VOL_ID)
+       if (vol_id == UBI_LAYOUT_VOLUME_ID)
                return UBI_LAYOUT_VOLUME_COMPAT;
        return 0;
 }
@@ -112,20 +89,20 @@ static int ubi_get_compat(const struct ubi_device *ubi, int vol_id)
  * @vol_id: volume ID
  * @lnum: logical eraseblock number
  *
- * This function returns a pointer to the corresponding &struct ltree_entry
+ * This function returns a pointer to the corresponding &struct ubi_ltree_entry
  * object if the logical eraseblock is locked and %NULL if it is not.
  * @ubi->ltree_lock has to be locked.
  */
-static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id,
-                                       int lnum)
+static struct ubi_ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id,
+                                           int lnum)
 {
        struct rb_node *p;
 
        p = ubi->ltree.rb_node;
        while (p) {
-               struct ltree_entry *le;
+               struct ubi_ltree_entry *le;
 
-               le = rb_entry(p, struct ltree_entry, rb);
+               le = rb_entry(p, struct ubi_ltree_entry, rb);
 
                if (vol_id < le->vol_id)
                        p = p->rb_left;
@@ -155,15 +132,17 @@ static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id,
  * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation
  * failed.
  */
-static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
-                                          int lnum)
+static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi,
+                                              int vol_id, int lnum)
 {
-       struct ltree_entry *le, *le1, *le_free;
+       struct ubi_ltree_entry *le, *le1, *le_free;
 
-       le = kmem_cache_alloc(ltree_slab, GFP_NOFS);
+       le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS);
        if (!le)
                return ERR_PTR(-ENOMEM);
 
+       le->users = 0;
+       init_rwsem(&le->mutex);
        le->vol_id = vol_id;
        le->lnum = lnum;
 
@@ -189,7 +168,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
                p = &ubi->ltree.rb_node;
                while (*p) {
                        parent = *p;
-                       le1 = rb_entry(parent, struct ltree_entry, rb);
+                       le1 = rb_entry(parent, struct ubi_ltree_entry, rb);
 
                        if (vol_id < le1->vol_id)
                                p = &(*p)->rb_left;
@@ -211,7 +190,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
        spin_unlock(&ubi->ltree_lock);
 
        if (le_free)
-               kmem_cache_free(ltree_slab, le_free);
+               kfree(le_free);
 
        return le;
 }
@@ -227,7 +206,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
  */
 static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum)
 {
-       struct ltree_entry *le;
+       struct ubi_ltree_entry *le;
 
        le = ltree_add_entry(ubi, vol_id, lnum);
        if (IS_ERR(le))
@@ -245,7 +224,7 @@ static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum)
 static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
 {
        int free = 0;
-       struct ltree_entry *le;
+       struct ubi_ltree_entry *le;
 
        spin_lock(&ubi->ltree_lock);
        le = ltree_lookup(ubi, vol_id, lnum);
@@ -259,7 +238,7 @@ static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
 
        up_read(&le->mutex);
        if (free)
-               kmem_cache_free(ltree_slab, le);
+               kfree(le);
 }
 
 /**
@@ -273,7 +252,7 @@ static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
  */
 static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
 {
-       struct ltree_entry *le;
+       struct ubi_ltree_entry *le;
 
        le = ltree_add_entry(ubi, vol_id, lnum);
        if (IS_ERR(le))
@@ -282,6 +261,44 @@ static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
        return 0;
 }
 
+/**
+ * leb_write_lock - lock logical eraseblock for writing.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function locks a logical eraseblock for writing if there is no
+ * contention and does nothing if there is contention. Returns %0 in case of
+ * success, %1 in case of contention, and and a negative error code in case of
+ * failure.
+ */
+static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+       int free;
+       struct ubi_ltree_entry *le;
+
+       le = ltree_add_entry(ubi, vol_id, lnum);
+       if (IS_ERR(le))
+               return PTR_ERR(le);
+       if (down_write_trylock(&le->mutex))
+               return 0;
+
+       /* Contention, cancel */
+       spin_lock(&ubi->ltree_lock);
+       le->users -= 1;
+       ubi_assert(le->users >= 0);
+       if (le->users == 0) {
+               rb_erase(&le->rb, &ubi->ltree);
+               free = 1;
+       } else
+               free = 0;
+       spin_unlock(&ubi->ltree_lock);
+       if (free)
+               kfree(le);
+
+       return 1;
+}
+
 /**
  * leb_write_unlock - unlock logical eraseblock.
  * @ubi: UBI device description object
@@ -291,7 +308,7 @@ static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
 static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
 {
        int free;
-       struct ltree_entry *le;
+       struct ubi_ltree_entry *le;
 
        spin_lock(&ubi->ltree_lock);
        le = ltree_lookup(ubi, vol_id, lnum);
@@ -306,23 +323,23 @@ static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
 
        up_write(&le->mutex);
        if (free)
-               kmem_cache_free(ltree_slab, le);
+               kfree(le);
 }
 
 /**
  * ubi_eba_unmap_leb - un-map logical eraseblock.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  *
  * This function un-maps logical eraseblock @lnum and schedules corresponding
  * physical eraseblock for erasure. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum)
+int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
+                     int lnum)
 {
-       int idx = vol_id2idx(ubi, vol_id), err, pnum;
-       struct ubi_volume *vol = ubi->volumes[idx];
+       int err, pnum, vol_id = vol->vol_id;
 
        if (ubi->ro_mode)
                return -EROFS;
@@ -349,7 +366,7 @@ out_unlock:
 /**
  * ubi_eba_read_leb - read data.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  * @buf: buffer to store the read data
  * @offset: offset from where to read
@@ -365,12 +382,11 @@ out_unlock:
  * returned for any volume type if an ECC error was detected by the MTD device
  * driver. Other negative error cored may be returned in case of other errors.
  */
-int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
-                    int offset, int len, int check)
+int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+                    void *buf, int offset, int len, int check)
 {
-       int err, pnum, scrub = 0, idx = vol_id2idx(ubi, vol_id);
+       int err, pnum, scrub = 0, vol_id = vol->vol_id;
        struct ubi_vid_hdr *vid_hdr;
-       struct ubi_volume *vol = ubi->volumes[idx];
        uint32_t uninitialized_var(crc);
 
        err = leb_read_lock(ubi, vol_id, lnum);
@@ -578,7 +594,7 @@ write_error:
 /**
  * ubi_eba_write_leb - write data to dynamic volume.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  * @buf: the data to write
  * @offset: offset within the logical eraseblock where to write
@@ -586,15 +602,14 @@ write_error:
  * @dtype: data type
  *
  * This function writes data to logical eraseblock @lnum of a dynamic volume
- * @vol_id. Returns zero in case of success and a negative error code in case
+ * @vol. Returns zero in case of success and a negative error code in case
  * of failure. In case of error, it is possible that something was still
  * written to the flash media, but may be some garbage.
  */
-int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
+int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
                      const void *buf, int offset, int len, int dtype)
 {
-       int idx = vol_id2idx(ubi, vol_id), err, pnum, tries = 0;
-       struct ubi_volume *vol = ubi->volumes[idx];
+       int err, pnum, tries = 0, vol_id = vol->vol_id;
        struct ubi_vid_hdr *vid_hdr;
 
        if (ubi->ro_mode)
@@ -613,7 +628,8 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
                if (err) {
                        ubi_warn("failed to write data to PEB %d", pnum);
                        if (err == -EIO && ubi->bad_allowed)
-                               err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len);
+                               err = recover_peb(ubi, pnum, vol_id, lnum, buf,
+                                                 offset, len);
                        if (err)
                                ubi_ro_mode(ubi);
                }
@@ -656,11 +672,14 @@ retry:
                goto write_error;
        }
 
-       err = ubi_io_write_data(ubi, buf, pnum, offset, len);
-       if (err) {
-               ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, "
-                        "PEB %d", len, offset, vol_id, lnum, pnum);
-               goto write_error;
+       if (len) {
+               err = ubi_io_write_data(ubi, buf, pnum, offset, len);
+               if (err) {
+                       ubi_warn("failed to write %d bytes at offset %d of "
+                                "LEB %d:%d, PEB %d", len, offset, vol_id,
+                                lnum, pnum);
+                       goto write_error;
+               }
        }
 
        vol->eba_tbl[lnum] = pnum;
@@ -698,7 +717,7 @@ write_error:
 /**
  * ubi_eba_write_leb_st - write data to static volume.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  * @buf: data to write
  * @len: how many bytes to write
@@ -706,7 +725,7 @@ write_error:
  * @used_ebs: how many logical eraseblocks will this volume contain
  *
  * This function writes data to logical eraseblock @lnum of static volume
- * @vol_id. The @used_ebs argument should contain total number of logical
+ * @vol. The @used_ebs argument should contain total number of logical
  * eraseblock in this static volume.
  *
  * When writing to the last logical eraseblock, the @len argument doesn't have
@@ -718,12 +737,11 @@ write_error:
  * volumes. This function returns zero in case of success and a negative error
  * code in case of failure.
  */
-int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
-                        const void *buf, int len, int dtype, int used_ebs)
+int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
+                        int lnum, const void *buf, int len, int dtype,
+                        int used_ebs)
 {
-       int err, pnum, tries = 0, data_size = len;
-       int idx = vol_id2idx(ubi, vol_id);
-       struct ubi_volume *vol = ubi->volumes[idx];
+       int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id;
        struct ubi_vid_hdr *vid_hdr;
        uint32_t crc;
 
@@ -819,7 +837,7 @@ write_error:
 /*
  * ubi_eba_atomic_leb_change - change logical eraseblock atomically.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  * @buf: data to write
  * @len: how many bytes to write
@@ -834,17 +852,27 @@ write_error:
  * UBI reserves one LEB for the "atomic LEB change" operation, so only one
  * LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
  */
-int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
-                             const void *buf, int len, int dtype)
+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+                             int lnum, const void *buf, int len, int dtype)
 {
-       int err, pnum, tries = 0, idx = vol_id2idx(ubi, vol_id);
-       struct ubi_volume *vol = ubi->volumes[idx];
+       int err, pnum, tries = 0, vol_id = vol->vol_id;
        struct ubi_vid_hdr *vid_hdr;
        uint32_t crc;
 
        if (ubi->ro_mode)
                return -EROFS;
 
+       if (len == 0) {
+               /*
+                * Special case when data length is zero. In this case the LEB
+                * has to be unmapped and mapped somewhere else.
+                */
+               err = ubi_eba_unmap_leb(ubi, vol, lnum);
+               if (err)
+                       return err;
+               return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+       }
+
        vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr)
                return -ENOMEM;
@@ -927,20 +955,6 @@ write_error:
        goto retry;
 }
 
-/**
- * ltree_entry_ctor - lock tree entries slab cache constructor.
- * @obj: the lock-tree entry to construct
- * @cache: the lock tree entry slab cache
- * @flags: constructor flags
- */
-static void ltree_entry_ctor(struct kmem_cache *cache, void *obj)
-{
-       struct ltree_entry *le = obj;
-
-       le->users = 0;
-       init_rwsem(&le->mutex);
-}
-
 /**
  * ubi_eba_copy_leb - copy logical eraseblock.
  * @ubi: UBI device description object
@@ -950,14 +964,16 @@ static void ltree_entry_ctor(struct kmem_cache *cache, void *obj)
  *
  * This function copies logical eraseblock from physical eraseblock @from to
  * physical eraseblock @to. The @vid_hdr buffer may be changed by this
- * function. Returns zero in case of success, %UBI_IO_BITFLIPS if the operation
- * was canceled because bit-flips were detected at the target PEB, and a
- * negative error code in case of failure.
+ * function. Returns:
+ *   o %0  in case of success;
+ *   o %1 if the operation was canceled and should be tried later (e.g.,
+ *     because a bit-flip was detected at the target PEB);
+ *   o %2 if the volume is being deleted and this LEB should not be moved.
  */
 int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                     struct ubi_vid_hdr *vid_hdr)
 {
-       int err, vol_id, lnum, data_size, aldata_size, pnum, idx;
+       int err, vol_id, lnum, data_size, aldata_size, idx;
        struct ubi_volume *vol;
        uint32_t crc;
 
@@ -973,51 +989,67 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                data_size = aldata_size =
                            ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
 
-       /*
-        * We do not want anybody to write to this logical eraseblock while we
-        * are moving it, so we lock it.
-        */
-       err = leb_write_lock(ubi, vol_id, lnum);
-       if (err)
-               return err;
-
-       mutex_lock(&ubi->buf_mutex);
-
-       /*
-        * But the logical eraseblock might have been put by this time.
-        * Cancel if it is true.
-        */
        idx = vol_id2idx(ubi, vol_id);
-
+       spin_lock(&ubi->volumes_lock);
        /*
-        * We may race with volume deletion/re-size, so we have to hold
-        * @ubi->volumes_lock.
+        * Note, we may race with volume deletion, which means that the volume
+        * this logical eraseblock belongs to might be being deleted. Since the
+        * volume deletion unmaps all the volume's logical eraseblocks, it will
+        * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish.
         */
-       spin_lock(&ubi->volumes_lock);
        vol = ubi->volumes[idx];
        if (!vol) {
-               dbg_eba("volume %d was removed meanwhile", vol_id);
+               /* No need to do further work, cancel */
+               dbg_eba("volume %d is being removed, cancel", vol_id);
                spin_unlock(&ubi->volumes_lock);
-               goto out_unlock;
+               return 2;
        }
+       spin_unlock(&ubi->volumes_lock);
 
-       pnum = vol->eba_tbl[lnum];
-       if (pnum != from) {
-               dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to "
-                       "PEB %d, cancel", vol_id, lnum, from, pnum);
-               spin_unlock(&ubi->volumes_lock);
-               goto out_unlock;
+       /*
+        * We do not want anybody to write to this logical eraseblock while we
+        * are moving it, so lock it.
+        *
+        * Note, we are using non-waiting locking here, because we cannot sleep
+        * on the LEB, since it may cause deadlocks. Indeed, imagine a task is
+        * unmapping the LEB which is mapped to the PEB we are going to move
+        * (@from). This task locks the LEB and goes sleep in the
+        * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are
+        * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the
+        * LEB is already locked, we just do not move it and return %1.
+        */
+       err = leb_write_trylock(ubi, vol_id, lnum);
+       if (err) {
+               dbg_eba("contention on LEB %d:%d, cancel", vol_id, lnum);
+               return err;
        }
-       spin_unlock(&ubi->volumes_lock);
 
-       /* OK, now the LEB is locked and we can safely start moving it */
+       /*
+        * The LEB might have been put meanwhile, and the task which put it is
+        * probably waiting on @ubi->move_mutex. No need to continue the work,
+        * cancel it.
+        */
+       if (vol->eba_tbl[lnum] != from) {
+               dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to "
+                       "PEB %d, cancel", vol_id, lnum, from,
+                       vol->eba_tbl[lnum]);
+               err = 1;
+               goto out_unlock_leb;
+       }
 
+       /*
+        * OK, now the LEB is locked and we can safely start moving iy. Since
+        * this function utilizes thie @ubi->peb1_buf buffer which is shared
+        * with some other functions, so lock the buffer by taking the
+        * @ubi->buf_mutex.
+        */
+       mutex_lock(&ubi->buf_mutex);
        dbg_eba("read %d bytes of data", aldata_size);
        err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
        if (err && err != UBI_IO_BITFLIPS) {
                ubi_warn("error %d while reading data from PEB %d",
                         err, from);
-               goto out_unlock;
+               goto out_unlock_buf;
        }
 
        /*
@@ -1053,7 +1085,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
 
        err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
        if (err)
-               goto out_unlock;
+               goto out_unlock_buf;
 
        cond_resched();
 
@@ -1062,13 +1094,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        if (err) {
                if (err != UBI_IO_BITFLIPS)
                        ubi_warn("cannot read VID header back from PEB %d", to);
-               goto out_unlock;
+               else
+                       err = 1;
+               goto out_unlock_buf;
        }
 
        if (data_size > 0) {
                err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
                if (err)
-                       goto out_unlock;
+                       goto out_unlock_buf;
 
                cond_resched();
 
@@ -1082,7 +1116,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                        if (err != UBI_IO_BITFLIPS)
                                ubi_warn("cannot read data back from PEB %d",
                                         to);
-                       goto out_unlock;
+                       else
+                               err = 1;
+                       goto out_unlock_buf;
                }
 
                cond_resched();
@@ -1090,15 +1126,16 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
                        ubi_warn("read data back from PEB %d - it is different",
                                 to);
-                       goto out_unlock;
+                       goto out_unlock_buf;
                }
        }
 
        ubi_assert(vol->eba_tbl[lnum] == from);
        vol->eba_tbl[lnum] = to;
 
-out_unlock:
+out_unlock_buf:
        mutex_unlock(&ubi->buf_mutex);
+out_unlock_leb:
        leb_write_unlock(ubi, vol_id, lnum);
        return err;
 }
@@ -1125,14 +1162,6 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
        mutex_init(&ubi->alc_mutex);
        ubi->ltree = RB_ROOT;
 
-       if (ubi_devices_cnt == 0) {
-               ltree_slab = kmem_cache_create("ubi_ltree_slab",
-                                              sizeof(struct ltree_entry), 0,
-                                              0, &ltree_entry_ctor);
-               if (!ltree_slab)
-                       return -ENOMEM;
-       }
-
        ubi->global_sqnum = si->max_sqnum + 1;
        num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
 
@@ -1168,6 +1197,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                }
        }
 
+       if (ubi->avail_pebs < EBA_RESERVED_PEBS) {
+               ubi_err("no enough physical eraseblocks (%d, need %d)",
+                       ubi->avail_pebs, EBA_RESERVED_PEBS);
+               err = -ENOSPC;
+               goto out_free;
+       }
+       ubi->avail_pebs -= EBA_RESERVED_PEBS;
+       ubi->rsvd_pebs += EBA_RESERVED_PEBS;
+
        if (ubi->bad_allowed) {
                ubi_calculate_reserved(ubi);
 
@@ -1184,15 +1222,6 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                ubi->rsvd_pebs  += ubi->beb_rsvd_pebs;
        }
 
-       if (ubi->avail_pebs < EBA_RESERVED_PEBS) {
-               ubi_err("no enough physical eraseblocks (%d, need %d)",
-                       ubi->avail_pebs, EBA_RESERVED_PEBS);
-               err = -ENOSPC;
-               goto out_free;
-       }
-       ubi->avail_pebs -= EBA_RESERVED_PEBS;
-       ubi->rsvd_pebs += EBA_RESERVED_PEBS;
-
        dbg_eba("EBA unit is initialized");
        return 0;
 
@@ -1202,8 +1231,6 @@ out_free:
                        continue;
                kfree(ubi->volumes[i]->eba_tbl);
        }
-       if (ubi_devices_cnt == 0)
-               kmem_cache_destroy(ltree_slab);
        return err;
 }
 
@@ -1222,6 +1249,4 @@ void ubi_eba_close(const struct ubi_device *ubi)
                        continue;
                kfree(ubi->volumes[i]->eba_tbl);
        }
-       if (ubi_devices_cnt == 1)
-               kmem_cache_destroy(ltree_slab);
 }
index 41ff74c60e1483d7a25d70f5df7832d77c603cb8..d397219238d3b8ede00b4075b1468c1922963d79 100644 (file)
@@ -129,8 +129,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
                if (to_read > total_read)
                        to_read = total_read;
 
-               err = ubi_eba_read_leb(ubi, vol->vol_id, lnum, buf, offs,
-                                      to_read, 0);
+               err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0);
                if (err)
                        break;
 
@@ -187,8 +186,8 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
                if (to_write > total_written)
                        to_write = total_written;
 
-               err = ubi_eba_write_leb(ubi, vol->vol_id, lnum, buf, offs,
-                                       to_write, UBI_UNKNOWN);
+               err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write,
+                                       UBI_UNKNOWN);
                if (err)
                        break;
 
@@ -237,7 +236,7 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
                return -EROFS;
 
        for (i = 0; i < count; i++) {
-               err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum + i);
+               err = ubi_eba_unmap_leb(ubi, vol, lnum + i);
                if (err)
                        goto out_err;
        }
index 7c304eec78b59ba8142a411a96ab4d925760052f..db3efdef2433884eccc04ad03a9de9d63f4d9af2 100644 (file)
@@ -173,6 +173,16 @@ retry:
                ubi_err("error %d while reading %d bytes from PEB %d:%d, "
                        "read %zd bytes", err, len, pnum, offset, read);
                ubi_dbg_dump_stack();
+
+               /*
+                * The driver should never return -EBADMSG if it failed to read
+                * all the requested data. But some buggy drivers might do
+                * this, so we change it to -EIO.
+                */
+               if (read != len && err == -EBADMSG) {
+                       ubi_assert(0);
+                       err = -EIO;
+               }
        } else {
                ubi_assert(len == read);
 
index 03c774f41549c8b2b56cfe5d9f125e00ceea8dd1..a70d58823f8d116804c4c05bfaf807cead9015e5 100644 (file)
  * @ubi_num: UBI device number
  * @di: the information is stored here
  *
- * This function returns %0 in case of success and a %-ENODEV if there is no
- * such UBI device.
+ * This function returns %0 in case of success, %-EINVAL if the UBI device
+ * number is invalid, and %-ENODEV if there is no such UBI device.
  */
 int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
 {
-       const struct ubi_device *ubi;
+       struct ubi_device *ubi;
+
+       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+               return -EINVAL;
 
-       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
-           !ubi_devices[ubi_num])
+       ubi = ubi_get_device(ubi_num);
+       if (!ubi)
                return -ENODEV;
 
-       ubi = ubi_devices[ubi_num];
        di->ubi_num = ubi->ubi_num;
        di->leb_size = ubi->leb_size;
        di->min_io_size = ubi->min_io_size;
        di->ro_mode = ubi->ro_mode;
-       di->cdev = MKDEV(ubi->major, 0);
+       di->cdev = ubi->cdev.dev;
+
+       ubi_put_device(ubi);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -73,7 +77,7 @@ void ubi_get_volume_info(struct ubi_volume_desc *desc,
        vi->usable_leb_size = vol->usable_leb_size;
        vi->name_len = vol->name_len;
        vi->name = vol->name;
-       vi->cdev = MKDEV(ubi->major, vi->vol_id + 1);
+       vi->cdev = vol->cdev.dev;
 }
 EXPORT_SYMBOL_GPL(ubi_get_volume_info);
 
@@ -104,37 +108,39 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
 
        dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
 
-       err = -ENODEV;
-       if (ubi_num < 0)
-               return ERR_PTR(err);
-
-       ubi = ubi_devices[ubi_num];
-
-       if (!try_module_get(THIS_MODULE))
-               return ERR_PTR(err);
-
-       if (ubi_num >= UBI_MAX_DEVICES || !ubi)
-               goto out_put;
+       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+               return ERR_PTR(-EINVAL);
 
-       err = -EINVAL;
-       if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
-               goto out_put;
        if (mode != UBI_READONLY && mode != UBI_READWRITE &&
            mode != UBI_EXCLUSIVE)
-               goto out_put;
+               return ERR_PTR(-EINVAL);
+
+       /*
+        * First of all, we have to get the UBI device to prevent its removal.
+        */
+       ubi = ubi_get_device(ubi_num);
+       if (!ubi)
+               return ERR_PTR(-ENODEV);
+
+       if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {
+               err = -EINVAL;
+               goto out_put_ubi;
+       }
 
        desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
        if (!desc) {
                err = -ENOMEM;
-               goto out_put;
+               goto out_put_ubi;
        }
 
+       err = -ENODEV;
+       if (!try_module_get(THIS_MODULE))
+               goto out_free;
+
        spin_lock(&ubi->volumes_lock);
        vol = ubi->volumes[vol_id];
-       if (!vol) {
-               err = -ENODEV;
+       if (!vol)
                goto out_unlock;
-       }
 
        err = -EBUSY;
        switch (mode) {
@@ -156,21 +162,19 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
                vol->exclusive = 1;
                break;
        }
+       get_device(&vol->dev);
+       vol->ref_count += 1;
        spin_unlock(&ubi->volumes_lock);
 
        desc->vol = vol;
        desc->mode = mode;
 
-       /*
-        * To prevent simultaneous checks of the same volume we use @vtbl_mutex,
-        * although it is not the purpose it was introduced for.
-        */
-       mutex_lock(&ubi->vtbl_mutex);
+       mutex_lock(&ubi->ckvol_mutex);
        if (!vol->checked) {
                /* This is the first open - check the volume */
                err = ubi_check_volume(ubi, vol_id);
                if (err < 0) {
-                       mutex_unlock(&ubi->vtbl_mutex);
+                       mutex_unlock(&ubi->ckvol_mutex);
                        ubi_close_volume(desc);
                        return ERR_PTR(err);
                }
@@ -181,14 +185,17 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
                }
                vol->checked = 1;
        }
-       mutex_unlock(&ubi->vtbl_mutex);
+       mutex_unlock(&ubi->ckvol_mutex);
+
        return desc;
 
 out_unlock:
        spin_unlock(&ubi->volumes_lock);
-       kfree(desc);
-out_put:
        module_put(THIS_MODULE);
+out_free:
+       kfree(desc);
+out_put_ubi:
+       ubi_put_device(ubi);
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(ubi_open_volume);
@@ -205,8 +212,8 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
                                           int mode)
 {
        int i, vol_id = -1, len;
-       struct ubi_volume_desc *ret;
        struct ubi_device *ubi;
+       struct ubi_volume_desc *ret;
 
        dbg_msg("open volume %s, mode %d", name, mode);
 
@@ -217,14 +224,12 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
        if (len > UBI_VOL_NAME_MAX)
                return ERR_PTR(-EINVAL);
 
-       ret = ERR_PTR(-ENODEV);
-       if (!try_module_get(THIS_MODULE))
-               return ret;
-
-       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi_devices[ubi_num])
-               goto out_put;
+       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+               return ERR_PTR(-EINVAL);
 
-       ubi = ubi_devices[ubi_num];
+       ubi = ubi_get_device(ubi_num);
+       if (!ubi)
+               return ERR_PTR(-ENODEV);
 
        spin_lock(&ubi->volumes_lock);
        /* Walk all volumes of this UBI device */
@@ -238,13 +243,16 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
        }
        spin_unlock(&ubi->volumes_lock);
 
-       if (vol_id < 0)
-               goto out_put;
+       if (vol_id >= 0)
+               ret = ubi_open_volume(ubi_num, vol_id, mode);
+       else
+               ret = ERR_PTR(-ENODEV);
 
-       ret = ubi_open_volume(ubi_num, vol_id, mode);
-
-out_put:
-       module_put(THIS_MODULE);
+       /*
+        * We should put the UBI device even in case of success, because
+        * 'ubi_open_volume()' took a reference as well.
+        */
+       ubi_put_device(ubi);
        return ret;
 }
 EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
@@ -256,10 +264,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
 void ubi_close_volume(struct ubi_volume_desc *desc)
 {
        struct ubi_volume *vol = desc->vol;
+       struct ubi_device *ubi = vol->ubi;
 
        dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode);
 
-       spin_lock(&vol->ubi->volumes_lock);
+       spin_lock(&ubi->volumes_lock);
        switch (desc->mode) {
        case UBI_READONLY:
                vol->readers -= 1;
@@ -270,9 +279,12 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
        case UBI_EXCLUSIVE:
                vol->exclusive = 0;
        }
-       spin_unlock(&vol->ubi->volumes_lock);
+       vol->ref_count -= 1;
+       spin_unlock(&ubi->volumes_lock);
 
        kfree(desc);
+       put_device(&vol->dev);
+       ubi_put_device(ubi);
        module_put(THIS_MODULE);
 }
 EXPORT_SYMBOL_GPL(ubi_close_volume);
@@ -332,7 +344,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
        if (len == 0)
                return 0;
 
-       err = ubi_eba_read_leb(ubi, vol_id, lnum, buf, offset, len, check);
+       err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
        if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) {
                ubi_warn("mark volume %d as corrupted", vol_id);
                vol->corrupted = 1;
@@ -399,7 +411,7 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
        if (len == 0)
                return 0;
 
-       return ubi_eba_write_leb(ubi, vol_id, lnum, buf, offset, len, dtype);
+       return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype);
 }
 EXPORT_SYMBOL_GPL(ubi_leb_write);
 
@@ -448,7 +460,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
        if (len == 0)
                return 0;
 
-       return ubi_eba_atomic_leb_change(ubi, vol_id, lnum, buf, len, dtype);
+       return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype);
 }
 EXPORT_SYMBOL_GPL(ubi_leb_change);
 
@@ -468,9 +480,9 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
 {
        struct ubi_volume *vol = desc->vol;
        struct ubi_device *ubi = vol->ubi;
-       int err, vol_id = vol->vol_id;
+       int err;
 
-       dbg_msg("erase LEB %d:%d", vol_id, lnum);
+       dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
 
        if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
                return -EROFS;
@@ -481,7 +493,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
        if (vol->upd_marker)
                return -EBADF;
 
-       err = ubi_eba_unmap_leb(ubi, vol_id, lnum);
+       err = ubi_eba_unmap_leb(ubi, vol, lnum);
        if (err)
                return err;
 
@@ -529,9 +541,8 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
 {
        struct ubi_volume *vol = desc->vol;
        struct ubi_device *ubi = vol->ubi;
-       int vol_id = vol->vol_id;
 
-       dbg_msg("unmap LEB %d:%d", vol_id, lnum);
+       dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);
 
        if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
                return -EROFS;
@@ -542,10 +553,54 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
        if (vol->upd_marker)
                return -EBADF;
 
-       return ubi_eba_unmap_leb(ubi, vol_id, lnum);
+       return ubi_eba_unmap_leb(ubi, vol, lnum);
 }
 EXPORT_SYMBOL_GPL(ubi_leb_unmap);
 
+/**
+ * ubi_leb_map - map logical erasblock to a physical eraseblock.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number
+ * @dtype: expected data type
+ *
+ * This function maps an un-mapped logical eraseblock @lnum to a physical
+ * eraseblock. This means, that after a successfull invocation of this
+ * function the logical eraseblock @lnum will be empty (contain only %0xFF
+ * bytes) and be mapped to a physical eraseblock, even if an unclean reboot
+ * happens.
+ *
+ * This function returns zero in case of success, %-EBADF if the volume is
+ * damaged because of an interrupted update, %-EBADMSG if the logical
+ * eraseblock is already mapped, and other negative error codes in case of
+ * other failures.
+ */
+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
+{
+       struct ubi_volume *vol = desc->vol;
+       struct ubi_device *ubi = vol->ubi;
+
+       dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);
+
+       if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+               return -EROFS;
+
+       if (lnum < 0 || lnum >= vol->reserved_pebs)
+               return -EINVAL;
+
+       if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
+           dtype != UBI_UNKNOWN)
+               return -EINVAL;
+
+       if (vol->upd_marker)
+               return -EBADF;
+
+       if (vol->eba_tbl[lnum] >= 0)
+               return -EBADMSG;
+
+       return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_map);
+
 /**
  * ubi_is_mapped - check if logical eraseblock is mapped.
  * @desc: volume descriptor
index 9e2338c8e2cf545f097bd74d6c1d7c20d26093bc..93e05281201292c4641d95593eb03158797d29a9 100644 (file)
@@ -79,7 +79,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
                else
                        size = vol->usable_leb_size;
 
-               err = ubi_eba_read_leb(ubi, vol_id, i, buf, 0, size, 1);
+               err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);
                if (err) {
                        if (err == -EBADMSG)
                                err = 1;
index c7b0afc9d2808e13b64ce2fae7d6755b2c99041e..05aa3e7daba1edefb88a3b97befb6d4f717fc25c 100644 (file)
@@ -286,9 +286,14 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
                 * FIXME: but this is anyway obsolete and will be removed at
                 * some point.
                 */
-
                dbg_bld("using old crappy leb_ver stuff");
 
+               if (v1 == v2) {
+                       ubi_err("PEB %d and PEB %d have the same version %lld",
+                               seb->pnum, pnum, v1);
+                       return -EINVAL;
+               }
+
                abs = v1 - v2;
                if (abs < 0)
                        abs = -abs;
@@ -390,7 +395,6 @@ out_free_buf:
        vfree(buf);
 out_free_vidh:
        ubi_free_vid_hdr(ubi, vh);
-       ubi_assert(err < 0);
        return err;
 }
 
@@ -769,7 +773,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
  */
 static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
 {
-       long long ec;
+       long long uninitialized_var(ec);
        int err, bitflips = 0, vol_id, ec_corr = 0;
 
        dbg_bld("scan PEB %d", pnum);
@@ -854,7 +858,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
        }
 
        vol_id = be32_to_cpu(vidh->vol_id);
-       if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
+       if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
                int lnum = be32_to_cpu(vidh->lnum);
 
                /* Unsupported internal volume */
index 5e941a6330303bc36271286a7861c4fdd5f63788..457710615261126e2fef2d2ad6463c991d83a895 100644 (file)
@@ -94,8 +94,43 @@ enum {
        UBI_IO_BITFLIPS
 };
 
-extern int ubi_devices_cnt;
-extern struct ubi_device *ubi_devices[];
+/**
+ * struct ubi_wl_entry - wear-leveling entry.
+ * @rb: link in the corresponding RB-tree
+ * @ec: erase counter
+ * @pnum: physical eraseblock number
+ *
+ * This data structure is used in the WL unit. Each physical eraseblock has a
+ * corresponding &struct wl_entry object which may be kept in different
+ * RB-trees. See WL unit for details.
+ */
+struct ubi_wl_entry {
+       struct rb_node rb;
+       int ec;
+       int pnum;
+};
+
+/**
+ * struct ubi_ltree_entry - an entry in the lock tree.
+ * @rb: links RB-tree nodes
+ * @vol_id: volume ID of the locked logical eraseblock
+ * @lnum: locked logical eraseblock number
+ * @users: how many tasks are using this logical eraseblock or wait for it
+ * @mutex: read/write mutex to implement read/write access serialization to
+ *         the (@vol_id, @lnum) logical eraseblock
+ *
+ * This data structure is used in the EBA unit to implement per-LEB locking.
+ * When a logical eraseblock is being locked - corresponding
+ * &struct ubi_ltree_entry object is inserted to the lock tree (@ubi->ltree).
+ * See EBA unit for details.
+ */
+struct ubi_ltree_entry {
+       struct rb_node rb;
+       int vol_id;
+       int lnum;
+       int users;
+       struct rw_semaphore mutex;
+};
 
 struct ubi_volume_desc;
 
@@ -105,11 +140,10 @@ struct ubi_volume_desc;
  * @cdev: character device object to create character device
  * @ubi: reference to the UBI device description object
  * @vol_id: volume ID
+ * @ref_count: volume reference count
  * @readers: number of users holding this volume in read-only mode
  * @writers: number of users holding this volume in read-write mode
  * @exclusive: whether somebody holds this volume in exclusive mode
- * @removed: if the volume was removed
- * @checked: if this static volume was checked
  *
  * @reserved_pebs: how many physical eraseblocks are reserved for this volume
  * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
@@ -117,21 +151,30 @@ struct ubi_volume_desc;
  * @used_ebs: how many logical eraseblocks in this volume contain data
  * @last_eb_bytes: how many bytes are stored in the last logical eraseblock
  * @used_bytes: how many bytes of data this volume contains
- * @upd_marker: non-zero if the update marker is set for this volume
- * @corrupted: non-zero if the volume is corrupted (static volumes only)
  * @alignment: volume alignment
  * @data_pad: how many bytes are not used at the end of physical eraseblocks to
- * satisfy the requested alignment
+ *            satisfy the requested alignment
  * @name_len: volume name length
  * @name: volume name
  *
- * @updating: whether the volume is being updated
  * @upd_ebs: how many eraseblocks are expected to be updated
- * @upd_bytes: how many bytes are expected to be received
- * @upd_received: how many update bytes were already received
- * @upd_buf: update buffer which is used to collect update data
+ * @ch_lnum: LEB number which is being changing by the atomic LEB change
+ *           operation
+ * @ch_dtype: data persistency type which is being changing by the atomic LEB
+ *            change operation
+ * @upd_bytes: how many bytes are expected to be received for volume update or
+ *             atomic LEB change
+ * @upd_received: how many bytes were already received for volume update or
+ *                atomic LEB change
+ * @upd_buf: update buffer which is used to collect update data or data for
+ *           atomic LEB change
  *
  * @eba_tbl: EBA table of this volume (LEB->PEB mapping)
+ * @checked: %1 if this static volume was checked
+ * @corrupted: %1 if the volume is corrupted (static volumes only)
+ * @upd_marker: %1 if the update marker is set for this volume
+ * @updating: %1 if the volume is being updated
+ * @changing_leb: %1 if the atomic LEB change ioctl command is in progress
  *
  * @gluebi_desc: gluebi UBI volume descriptor
  * @gluebi_refcount: reference count of the gluebi MTD device
@@ -150,11 +193,10 @@ struct ubi_volume {
        struct cdev cdev;
        struct ubi_device *ubi;
        int vol_id;
+       int ref_count;
        int readers;
        int writers;
        int exclusive;
-       int removed;
-       int checked;
 
        int reserved_pebs;
        int vol_type;
@@ -162,23 +204,31 @@ struct ubi_volume {
        int used_ebs;
        int last_eb_bytes;
        long long used_bytes;
-       int upd_marker;
-       int corrupted;
        int alignment;
        int data_pad;
        int name_len;
        char name[UBI_VOL_NAME_MAX+1];
 
-       int updating;
        int upd_ebs;
+       int ch_lnum;
+       int ch_dtype;
        long long upd_bytes;
        long long upd_received;
        void *upd_buf;
 
        int *eba_tbl;
+       int checked:1;
+       int corrupted:1;
+       int upd_marker:1;
+       int updating:1;
+       int changing_leb:1;
 
 #ifdef CONFIG_MTD_UBI_GLUEBI
-       /* Gluebi-related stuff may be compiled out */
+       /*
+        * Gluebi-related stuff may be compiled out.
+        * TODO: this should not be built into UBI but should be a separate
+        * ubimtd driver which works on top of UBI and emulates MTD devices.
+        */
        struct ubi_volume_desc *gluebi_desc;
        int gluebi_refcount;
        struct mtd_info gluebi_mtd;
@@ -200,28 +250,31 @@ struct ubi_wl_entry;
 
 /**
  * struct ubi_device - UBI device description structure
- * @dev: class device object to use the the Linux device model
+ * @dev: UBI device object to use the the Linux device model
  * @cdev: character device object to create character device
  * @ubi_num: UBI device number
  * @ubi_name: UBI device name
- * @major: character device major number
  * @vol_count: number of volumes in this UBI device
  * @volumes: volumes of this UBI device
  * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,
- * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, @vol->readers,
- * @vol->writers, @vol->exclusive, @vol->removed, @vol->mapping and
- * @vol->eba_tbl.
+ *                @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
+ *                @vol->readers, @vol->writers, @vol->exclusive,
+ *                @vol->ref_count, @vol->mapping and @vol->eba_tbl.
+ * @ref_count: count of references on the UBI device
  *
  * @rsvd_pebs: count of reserved physical eraseblocks
  * @avail_pebs: count of available physical eraseblocks
  * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB
- * handling
+ *                 handling
  * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling
  *
+ * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end
+ *                     of UBI ititializetion
  * @vtbl_slots: how many slots are available in the volume table
  * @vtbl_size: size of the volume table in bytes
  * @vtbl: in-RAM volume table copy
- * @vtbl_mutex: protects on-flash volume table
+ * @volumes_mutex: protects on-flash volume table and serializes volume
+ *                 changes, like creation, deletion, update, resize
  *
  * @max_ec: current highest erase counter value
  * @mean_ec: current mean erase counter value
@@ -238,15 +291,15 @@ struct ubi_wl_entry;
  * @prot.pnum: protection tree indexed by physical eraseblock numbers
  * @prot.aec: protection tree indexed by absolute erase counter value
  * @wl_lock: protects the @used, @free, @prot, @lookuptbl, @abs_ec, @move_from,
- * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works
- * fields
+ *           @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works
+ *           fields
+ * @move_mutex: serializes eraseblock moves
  * @wl_scheduled: non-zero if the wear-leveling was scheduled
  * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any
- * physical eraseblock
+ *             physical eraseblock
  * @abs_ec: absolute erase counter
  * @move_from: physical eraseblock from where the data is being moved
  * @move_to: physical eraseblock where the data is being moved to
- * @move_from_put: if the "from" PEB was put
  * @move_to_put: if the "to" PEB was put
  * @works: list of pending works
  * @works_count: count of pending works
@@ -273,13 +326,13 @@ struct ubi_wl_entry;
  * @hdrs_min_io_size
  * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
  * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
- * not
+ *               not
  * @mtd: MTD device descriptor
  *
  * @peb_buf1: a buffer of PEB size used for different purposes
  * @peb_buf2: another buffer of PEB size used for different purposes
  * @buf_mutex: proptects @peb_buf1 and @peb_buf2
- * @dbg_peb_buf:  buffer of PEB size used for debugging
+ * @dbg_peb_buf: buffer of PEB size used for debugging
  * @dbg_buf_mutex: proptects @dbg_peb_buf
  */
 struct ubi_device {
@@ -287,22 +340,24 @@ struct ubi_device {
        struct device dev;
        int ubi_num;
        char ubi_name[sizeof(UBI_NAME_STR)+5];
-       int major;
        int vol_count;
        struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
        spinlock_t volumes_lock;
+       int ref_count;
 
        int rsvd_pebs;
        int avail_pebs;
        int beb_rsvd_pebs;
        int beb_rsvd_level;
 
+       int autoresize_vol_id;
        int vtbl_slots;
        int vtbl_size;
        struct ubi_vtbl_record *vtbl;
-       struct mutex vtbl_mutex;
+       struct mutex volumes_mutex;
 
        int max_ec;
+       /* TODO: mean_ec is not updated run-time, fix */
        int mean_ec;
 
        /* EBA unit's stuff */
@@ -320,12 +375,13 @@ struct ubi_device {
                struct rb_root aec;
        } prot;
        spinlock_t wl_lock;
+       struct mutex move_mutex;
+       struct rw_semaphore work_sem;
        int wl_scheduled;
        struct ubi_wl_entry **lookuptbl;
        unsigned long long abs_ec;
        struct ubi_wl_entry *move_from;
        struct ubi_wl_entry *move_to;
-       int move_from_put;
        int move_to_put;
        struct list_head works;
        int works_count;
@@ -355,15 +411,19 @@ struct ubi_device {
        void *peb_buf1;
        void *peb_buf2;
        struct mutex buf_mutex;
+       struct mutex ckvol_mutex;
 #ifdef CONFIG_MTD_UBI_DEBUG
        void *dbg_peb_buf;
        struct mutex dbg_buf_mutex;
 #endif
 };
 
+extern struct kmem_cache *ubi_wl_entry_slab;
+extern struct file_operations ubi_ctrl_cdev_operations;
 extern struct file_operations ubi_cdev_operations;
 extern struct file_operations ubi_vol_cdev_operations;
 extern struct class *ubi_class;
+extern struct mutex ubi_devices_mutex;
 
 /* vtbl.c */
 int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
@@ -374,13 +434,18 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si);
 int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req);
 int ubi_remove_volume(struct ubi_volume_desc *desc);
 int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs);
-int ubi_add_volume(struct ubi_device *ubi, int vol_id);
-void ubi_free_volume(struct ubi_device *ubi, int vol_id);
+int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol);
+void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol);
 
 /* upd.c */
-int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes);
-int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
+int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
+                    long long bytes);
+int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
                         const void __user *buf, int count);
+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+                        const struct ubi_leb_change_req *req);
+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
+                            const void __user *buf, int count);
 
 /* misc.c */
 int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length);
@@ -399,16 +464,17 @@ void ubi_gluebi_updated(struct ubi_volume *vol);
 #endif
 
 /* eba.c */
-int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum);
-int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
-                    int offset, int len, int check);
-int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
+int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
+                     int lnum);
+int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+                    void *buf, int offset, int len, int check);
+int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
                      const void *buf, int offset, int len, int dtype);
-int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
-                        const void *buf, int len, int dtype,
+int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
+                        int lnum, const void *buf, int len, int dtype,
                         int used_ebs);
-int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
-                             const void *buf, int len, int dtype);
+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+                             int lnum, const void *buf, int len, int dtype);
 int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                     struct ubi_vid_hdr *vid_hdr);
 int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
@@ -421,6 +487,7 @@ int ubi_wl_flush(struct ubi_device *ubi);
 int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
 int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
 void ubi_wl_close(struct ubi_device *ubi);
+int ubi_thread(void *u);
 
 /* io.c */
 int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
@@ -439,6 +506,14 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
 int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
                         struct ubi_vid_hdr *vid_hdr);
 
+/* build.c */
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset);
+int ubi_detach_mtd_dev(int ubi_num, int anyway);
+struct ubi_device *ubi_get_device(int ubi_num);
+void ubi_put_device(struct ubi_device *ubi);
+struct ubi_device *ubi_get_by_major(int major);
+int ubi_major2num(int major);
+
 /*
  * ubi_rb_for_each_entry - walk an RB-tree.
  * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
@@ -523,8 +598,10 @@ static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf,
  */
 static inline void ubi_ro_mode(struct ubi_device *ubi)
 {
-       ubi->ro_mode = 1;
-       ubi_warn("switch to read-only mode");
+       if (!ubi->ro_mode) {
+               ubi->ro_mode = 1;
+               ubi_warn("switch to read-only mode");
+       }
 }
 
 /**
index 0efc586a83288fd5ccde9bc6b39a5ea432cf8f4c..ddaa1a56cc692d278f16e1f92cc9a799fcd72b90 100644 (file)
@@ -22,7 +22,8 @@
  */
 
 /*
- * This file contains implementation of the volume update functionality.
+ * This file contains implementation of the volume update and atomic LEB change
+ * functionality.
  *
  * The update operation is based on the per-volume update marker which is
  * stored in the volume table. The update marker is set before the update
 /**
  * set_update_marker - set update marker.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  *
- * This function sets the update marker flag for volume @vol_id. Returns zero
+ * This function sets the update marker flag for volume @vol. Returns zero
  * in case of success and a negative error code in case of failure.
  */
-static int set_update_marker(struct ubi_device *ubi, int vol_id)
+static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol)
 {
        int err;
        struct ubi_vtbl_record vtbl_rec;
-       struct ubi_volume *vol = ubi->volumes[vol_id];
 
-       dbg_msg("set update marker for volume %d", vol_id);
+       dbg_msg("set update marker for volume %d", vol->vol_id);
 
        if (vol->upd_marker) {
-               ubi_assert(ubi->vtbl[vol_id].upd_marker);
+               ubi_assert(ubi->vtbl[vol->vol_id].upd_marker);
                dbg_msg("already set");
                return 0;
        }
 
-       memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
+       memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
+              sizeof(struct ubi_vtbl_record));
        vtbl_rec.upd_marker = 1;
 
-       err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+       mutex_lock(&ubi->volumes_mutex);
+       err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
+       mutex_unlock(&ubi->volumes_mutex);
        vol->upd_marker = 1;
        return err;
 }
@@ -75,23 +78,24 @@ static int set_update_marker(struct ubi_device *ubi, int vol_id)
 /**
  * clear_update_marker - clear update marker.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @bytes: new data size in bytes
  *
- * This function clears the update marker for volume @vol_id, sets new volume
+ * This function clears the update marker for volume @vol, sets new volume
  * data size and clears the "corrupted" flag (static volumes only). Returns
  * zero in case of success and a negative error code in case of failure.
  */
-static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long bytes)
+static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol,
+                              long long bytes)
 {
        int err;
        uint64_t tmp;
        struct ubi_vtbl_record vtbl_rec;
-       struct ubi_volume *vol = ubi->volumes[vol_id];
 
-       dbg_msg("clear update marker for volume %d", vol_id);
+       dbg_msg("clear update marker for volume %d", vol->vol_id);
 
-       memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
+       memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
+              sizeof(struct ubi_vtbl_record));
        ubi_assert(vol->upd_marker && vtbl_rec.upd_marker);
        vtbl_rec.upd_marker = 0;
 
@@ -106,7 +110,9 @@ static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long byt
                        vol->last_eb_bytes = vol->usable_leb_size;
        }
 
-       err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+       mutex_lock(&ubi->volumes_mutex);
+       err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
+       mutex_unlock(&ubi->volumes_mutex);
        vol->upd_marker = 0;
        return err;
 }
@@ -114,35 +120,36 @@ static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long byt
 /**
  * ubi_start_update - start volume update.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @bytes: update bytes
  *
  * This function starts volume update operation. If @bytes is zero, the volume
  * is just wiped out. Returns zero in case of success and a negative error code
  * in case of failure.
  */
-int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
+int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
+                    long long bytes)
 {
        int i, err;
        uint64_t tmp;
-       struct ubi_volume *vol = ubi->volumes[vol_id];
 
-       dbg_msg("start update of volume %d, %llu bytes", vol_id, bytes);
+       dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes);
+       ubi_assert(!vol->updating && !vol->changing_leb);
        vol->updating = 1;
 
-       err = set_update_marker(ubi, vol_id);
+       err = set_update_marker(ubi, vol);
        if (err)
                return err;
 
        /* Before updating - wipe out the volume */
        for (i = 0; i < vol->reserved_pebs; i++) {
-               err = ubi_eba_unmap_leb(ubi, vol_id, i);
+               err = ubi_eba_unmap_leb(ubi, vol, i);
                if (err)
                        return err;
        }
 
        if (bytes == 0) {
-               err = clear_update_marker(ubi, vol_id, 0);
+               err = clear_update_marker(ubi, vol, 0);
                if (err)
                        return err;
                err = ubi_wl_flush(ubi);
@@ -162,10 +169,43 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
        return 0;
 }
 
+/**
+ * ubi_start_leb_change - start atomic LEB change.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @req: operation request
+ *
+ * This function starts atomic LEB change operation. Returns zero in case of
+ * success and a negative error code in case of failure.
+ */
+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+                        const struct ubi_leb_change_req *req)
+{
+       ubi_assert(!vol->updating && !vol->changing_leb);
+
+       dbg_msg("start changing LEB %d:%d, %u bytes",
+               vol->vol_id, req->lnum, req->bytes);
+       if (req->bytes == 0)
+               return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0,
+                                                req->dtype);
+
+       vol->upd_bytes = req->bytes;
+       vol->upd_received = 0;
+       vol->changing_leb = 1;
+       vol->ch_lnum = req->lnum;
+       vol->ch_dtype = req->dtype;
+
+       vol->upd_buf = vmalloc(req->bytes);
+       if (!vol->upd_buf)
+               return -ENOMEM;
+
+       return 0;
+}
+
 /**
  * write_leb - write update data.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  * @buf: data to write
  * @len: data size
@@ -191,26 +231,22 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
  * This function returns zero in case of success and a negative error code in
  * case of failure.
  */
-static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
-                    int len, int used_ebs)
+static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+                    void *buf, int len, int used_ebs)
 {
-       int err, l;
-       struct ubi_volume *vol = ubi->volumes[vol_id];
+       int err;
 
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
-               l = ALIGN(len, ubi->min_io_size);
-               memset(buf + len, 0xFF, l - len);
+               len = ALIGN(len, ubi->min_io_size);
+               memset(buf + len, 0xFF, len - len);
 
-               l = ubi_calc_data_len(ubi, buf, l);
-               if (l == 0) {
+               len = ubi_calc_data_len(ubi, buf, len);
+               if (len == 0) {
                        dbg_msg("all %d bytes contain 0xFF - skip", len);
                        return 0;
                }
-               if (len != l)
-                       dbg_msg("skip last %d bytes (0xFF)", len - l);
 
-               err = ubi_eba_write_leb(ubi, vol_id, lnum, buf, 0, l,
-                                       UBI_UNKNOWN);
+               err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN);
        } else {
                /*
                 * When writing static volume, and this is the last logical
@@ -222,7 +258,7 @@ static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
                 * contain zeros, not random trash.
                 */
                memset(buf + len, 0, vol->usable_leb_size - len);
-               err = ubi_eba_write_leb_st(ubi, vol_id, lnum, buf, len,
+               err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len,
                                           UBI_UNKNOWN, used_ebs);
        }
 
@@ -236,16 +272,15 @@ static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
  * @count: how much bytes to write
  *
  * This function writes more data to the volume which is being updated. It may
- * be called arbitrary number of times until all of the update data arrive.
- * This function returns %0 in case of success, number of bytes written during
- * the last call if the whole volume update was successfully finished, and a
+ * be called arbitrary number of times until all the update data arriveis. This
+ * function returns %0 in case of success, number of bytes written during the
+ * last call if the whole volume update has been successfully finished, and a
  * negative error code in case of failure.
  */
-int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
+int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
                         const void __user *buf, int count)
 {
        uint64_t tmp;
-       struct ubi_volume *vol = ubi->volumes[vol_id];
        int lnum, offs, err = 0, len, to_write = count;
 
        dbg_msg("write %d of %lld bytes, %lld already passed",
@@ -290,8 +325,8 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
                         * is the last chunk, it's time to flush the buffer.
                         */
                        ubi_assert(flush_len <= vol->usable_leb_size);
-                       err = write_leb(ubi, vol_id, lnum, vol->upd_buf,
-                                       flush_len, vol->upd_ebs);
+                       err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len,
+                                       vol->upd_ebs);
                        if (err)
                                return err;
                }
@@ -318,8 +353,8 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
 
                if (len == vol->usable_leb_size ||
                    vol->upd_received + len == vol->upd_bytes) {
-                       err = write_leb(ubi, vol_id, lnum, vol->upd_buf, len,
-                                       vol->upd_ebs);
+                       err = write_leb(ubi, vol, lnum, vol->upd_buf,
+                                       len, vol->upd_ebs);
                        if (err)
                                break;
                }
@@ -333,16 +368,70 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
        ubi_assert(vol->upd_received <= vol->upd_bytes);
        if (vol->upd_received == vol->upd_bytes) {
                /* The update is finished, clear the update marker */
-               err = clear_update_marker(ubi, vol_id, vol->upd_bytes);
+               err = clear_update_marker(ubi, vol, vol->upd_bytes);
                if (err)
                        return err;
                err = ubi_wl_flush(ubi);
                if (err == 0) {
+                       vol->updating = 0;
                        err = to_write;
                        vfree(vol->upd_buf);
-                       vol->updating = 0;
                }
        }
 
        return err;
 }
+
+/**
+ * ubi_more_leb_change_data - accept more data for atomic LEB change.
+ * @vol: volume description object
+ * @buf: write data (user-space memory buffer)
+ * @count: how much bytes to write
+ *
+ * This function accepts more data to the volume which is being under the
+ * "atomic LEB change" operation. It may be called arbitrary number of times
+ * until all data arrives. This function returns %0 in case of success, number
+ * of bytes written during the last call if the whole "atomic LEB change"
+ * operation has been successfully finished, and a negative error code in case
+ * of failure.
+ */
+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
+                            const void __user *buf, int count)
+{
+       int err;
+
+       dbg_msg("write %d of %lld bytes, %lld already passed",
+               count, vol->upd_bytes, vol->upd_received);
+
+       if (ubi->ro_mode)
+               return -EROFS;
+
+       if (vol->upd_received + count > vol->upd_bytes)
+               count = vol->upd_bytes - vol->upd_received;
+
+       err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count);
+       if (err)
+               return -EFAULT;
+
+       vol->upd_received += count;
+
+       if (vol->upd_received == vol->upd_bytes) {
+               int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size);
+
+               memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes);
+               len = ubi_calc_data_len(ubi, vol->upd_buf, len);
+               err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
+                                               vol->upd_buf, len, UBI_UNKNOWN);
+               if (err)
+                       return err;
+       }
+
+       ubi_assert(vol->upd_received <= vol->upd_bytes);
+       if (vol->upd_received == vol->upd_bytes) {
+               vol->changing_leb = 0;
+               err = count;
+               vfree(vol->upd_buf);
+       }
+
+       return err;
+}
index 88629a320c2b191823035fab474f552b79328a75..a3ca2257e6015e586ddcbfa513acb760b01afb08 100644 (file)
@@ -63,21 +63,30 @@ static struct device_attribute attr_vol_upd_marker =
  * B. process 2 removes volume Y;
  * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file;
  *
- * What we want to do in a situation like that is to return error when the file
- * is read. This is done by means of the 'removed' flag and the 'vol_lock' of
- * the UBI volume description object.
+ * In this situation, this function will return %-ENODEV because it will find
+ * out that the volume was removed from the @ubi->volumes array.
  */
 static ssize_t vol_attribute_show(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
        int ret;
        struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
+       struct ubi_device *ubi;
 
-       spin_lock(&vol->ubi->volumes_lock);
-       if (vol->removed) {
-               spin_unlock(&vol->ubi->volumes_lock);
+       ubi = ubi_get_device(vol->ubi->ubi_num);
+       if (!ubi)
+               return -ENODEV;
+
+       spin_lock(&ubi->volumes_lock);
+       if (!ubi->volumes[vol->vol_id]) {
+               spin_unlock(&ubi->volumes_lock);
+               ubi_put_device(ubi);
                return -ENODEV;
        }
+       /* Take a reference to prevent volume removal */
+       vol->ref_count += 1;
+       spin_unlock(&ubi->volumes_lock);
+
        if (attr == &attr_vol_reserved_ebs)
                ret = sprintf(buf, "%d\n", vol->reserved_pebs);
        else if (attr == &attr_vol_type) {
@@ -94,15 +103,22 @@ static ssize_t vol_attribute_show(struct device *dev,
                ret = sprintf(buf, "%d\n", vol->corrupted);
        else if (attr == &attr_vol_alignment)
                ret = sprintf(buf, "%d\n", vol->alignment);
-       else if (attr == &attr_vol_usable_eb_size) {
+       else if (attr == &attr_vol_usable_eb_size)
                ret = sprintf(buf, "%d\n", vol->usable_leb_size);
-       else if (attr == &attr_vol_data_bytes)
+       else if (attr == &attr_vol_data_bytes)
                ret = sprintf(buf, "%lld\n", vol->used_bytes);
        else if (attr == &attr_vol_upd_marker)
                ret = sprintf(buf, "%d\n", vol->upd_marker);
        else
-               BUG();
-       spin_unlock(&vol->ubi->volumes_lock);
+               /* This must be a bug */
+               ret = -EINVAL;
+
+       /* We've done the operation, drop volume and UBI device references */
+       spin_lock(&ubi->volumes_lock);
+       vol->ref_count -= 1;
+       ubi_assert(vol->ref_count >= 0);
+       spin_unlock(&ubi->volumes_lock);
+       ubi_put_device(ubi);
        return ret;
 }
 
@@ -110,7 +126,7 @@ static ssize_t vol_attribute_show(struct device *dev,
 static void vol_release(struct device *dev)
 {
        struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
-       ubi_assert(vol->removed);
+
        kfree(vol);
 }
 
@@ -152,9 +168,7 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
        if (err)
                return err;
        err = device_create_file(&vol->dev, &attr_vol_upd_marker);
-       if (err)
-               return err;
-       return 0;
+       return err;
 }
 
 /**
@@ -180,16 +194,18 @@ static void volume_sysfs_close(struct ubi_volume *vol)
  * @req: volume creation request
  *
  * This function creates volume described by @req. If @req->vol_id id
- * %UBI_VOL_NUM_AUTO, this function automatically assigne ID to the new volume
+ * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume
  * and saves it in @req->vol_id. Returns zero in case of success and a negative
- * error code in case of failure.
+ * error code in case of failure. Note, the caller has to have the
+ * @ubi->volumes_mutex locked.
  */
 int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 {
-       int i, err, vol_id = req->vol_id;
+       int i, err, vol_id = req->vol_id, dont_free = 0;
        struct ubi_volume *vol;
        struct ubi_vtbl_record vtbl_rec;
        uint64_t bytes;
+       dev_t dev;
 
        if (ubi->ro_mode)
                return -EROFS;
@@ -199,7 +215,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
                return -ENOMEM;
 
        spin_lock(&ubi->volumes_lock);
-
        if (vol_id == UBI_VOL_NUM_AUTO) {
                /* Find unused volume ID */
                dbg_msg("search for vacant volume ID");
@@ -252,6 +267,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        }
        ubi->avail_pebs -= vol->reserved_pebs;
        ubi->rsvd_pebs += vol->reserved_pebs;
+       spin_unlock(&ubi->volumes_lock);
 
        vol->vol_id    = vol_id;
        vol->alignment = req->alignment;
@@ -259,10 +275,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        vol->vol_type  = req->vol_type;
        vol->name_len  = req->name_len;
        memcpy(vol->name, req->name, vol->name_len + 1);
-       vol->exclusive = 1;
        vol->ubi = ubi;
-       ubi->volumes[vol_id] = vol;
-       spin_unlock(&ubi->volumes_lock);
 
        /*
         * Finish all pending erases because there may be some LEBs belonging
@@ -299,9 +312,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        /* Register character device for the volume */
        cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
        vol->cdev.owner = THIS_MODULE;
-       err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol_id + 1), 1);
+       dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);
+       err = cdev_add(&vol->cdev, dev, 1);
        if (err) {
-               ubi_err("cannot add character device for volume %d", vol_id);
+               ubi_err("cannot add character device");
                goto out_mapping;
        }
 
@@ -311,12 +325,15 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 
        vol->dev.release = vol_release;
        vol->dev.parent = &ubi->dev;
-       vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1);
+       vol->dev.devt = dev;
        vol->dev.class = ubi_class;
+
        sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
        err = device_register(&vol->dev);
-       if (err)
+       if (err) {
+               ubi_err("cannot register device");
                goto out_gluebi;
+       }
 
        err = volume_sysfs_init(ubi, vol);
        if (err)
@@ -339,15 +356,27 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
                goto out_sysfs;
 
        spin_lock(&ubi->volumes_lock);
+       ubi->volumes[vol_id] = vol;
        ubi->vol_count += 1;
-       vol->exclusive = 0;
        spin_unlock(&ubi->volumes_lock);
 
        paranoid_check_volumes(ubi);
        return 0;
 
+out_sysfs:
+       /*
+        * We have registered our device, we should not free the volume*
+        * description object in this function in case of an error - it is
+        * freed by the release function.
+        *
+        * Get device reference to prevent the release function from being
+        * called just after sysfs has been closed.
+        */
+       dont_free = 1;
+       get_device(&vol->dev);
+       volume_sysfs_close(vol);
 out_gluebi:
-       err = ubi_destroy_gluebi(vol);
+       ubi_destroy_gluebi(vol);
 out_cdev:
        cdev_del(&vol->cdev);
 out_mapping:
@@ -356,26 +385,13 @@ out_acc:
        spin_lock(&ubi->volumes_lock);
        ubi->rsvd_pebs -= vol->reserved_pebs;
        ubi->avail_pebs += vol->reserved_pebs;
-       ubi->volumes[vol_id] = NULL;
 out_unlock:
        spin_unlock(&ubi->volumes_lock);
-       kfree(vol);
-       return err;
-
-       /*
-        * We are registered, so @vol is destroyed in the release function and
-        * we have to de-initialize differently.
-        */
-out_sysfs:
-       err = ubi_destroy_gluebi(vol);
-       cdev_del(&vol->cdev);
-       kfree(vol->eba_tbl);
-       spin_lock(&ubi->volumes_lock);
-       ubi->rsvd_pebs -= vol->reserved_pebs;
-       ubi->avail_pebs += vol->reserved_pebs;
-       ubi->volumes[vol_id] = NULL;
-       spin_unlock(&ubi->volumes_lock);
-       volume_sysfs_close(vol);
+       if (dont_free)
+               put_device(&vol->dev);
+       else
+               kfree(vol);
+       ubi_err("cannot create volume %d, error %d", vol_id, err);
        return err;
 }
 
@@ -385,7 +401,8 @@ out_sysfs:
  *
  * This function removes volume described by @desc. The volume has to be opened
  * in "exclusive" mode. Returns zero in case of success and a negative error
- * code in case of failure.
+ * code in case of failure. The caller has to have the @ubi->volumes_mutex
+ * locked.
  */
 int ubi_remove_volume(struct ubi_volume_desc *desc)
 {
@@ -400,30 +417,36 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
        if (ubi->ro_mode)
                return -EROFS;
 
+       spin_lock(&ubi->volumes_lock);
+       if (vol->ref_count > 1) {
+               /*
+                * The volume is busy, probably someone is reading one of its
+                * sysfs files.
+                */
+               err = -EBUSY;
+               goto out_unlock;
+       }
+       ubi->volumes[vol_id] = NULL;
+       spin_unlock(&ubi->volumes_lock);
+
        err = ubi_destroy_gluebi(vol);
        if (err)
-               return err;
+               goto out_err;
 
        err = ubi_change_vtbl_record(ubi, vol_id, NULL);
        if (err)
-               return err;
+               goto out_err;
 
        for (i = 0; i < vol->reserved_pebs; i++) {
-               err = ubi_eba_unmap_leb(ubi, vol_id, i);
+               err = ubi_eba_unmap_leb(ubi, vol, i);
                if (err)
-                       return err;
+                       goto out_err;
        }
 
-       spin_lock(&ubi->volumes_lock);
-       vol->removed = 1;
-       ubi->volumes[vol_id] = NULL;
-       spin_unlock(&ubi->volumes_lock);
-
        kfree(vol->eba_tbl);
        vol->eba_tbl = NULL;
        cdev_del(&vol->cdev);
        volume_sysfs_close(vol);
-       kfree(desc);
 
        spin_lock(&ubi->volumes_lock);
        ubi->rsvd_pebs -= reserved_pebs;
@@ -441,8 +464,15 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
        spin_unlock(&ubi->volumes_lock);
 
        paranoid_check_volumes(ubi);
-       module_put(THIS_MODULE);
        return 0;
+
+out_err:
+       ubi_err("cannot remove volume %d, error %d", vol_id, err);
+       spin_lock(&ubi->volumes_lock);
+       ubi->volumes[vol_id] = vol;
+out_unlock:
+       spin_unlock(&ubi->volumes_lock);
+       return err;
 }
 
 /**
@@ -450,8 +480,9 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
  * @desc: volume descriptor
  * @reserved_pebs: new size in physical eraseblocks
  *
- * This function returns zero in case of success, and a negative error code in
- * case of failure.
+ * This function re-sizes the volume and returns zero in case of success, and a
+ * negative error code in case of failure. The caller has to have the
+ * @ubi->volumes_mutex locked.
  */
 int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
 {
@@ -466,8 +497,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
 
        dbg_msg("re-size volume %d to from %d to %d PEBs",
                vol_id, vol->reserved_pebs, reserved_pebs);
-       ubi_assert(desc->mode == UBI_EXCLUSIVE);
-       ubi_assert(vol == ubi->volumes[vol_id]);
 
        if (vol->vol_type == UBI_STATIC_VOLUME &&
            reserved_pebs < vol->used_ebs) {
@@ -487,6 +516,14 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
        for (i = 0; i < reserved_pebs; i++)
                new_mapping[i] = UBI_LEB_UNMAPPED;
 
+       spin_lock(&ubi->volumes_lock);
+       if (vol->ref_count > 1) {
+               spin_unlock(&ubi->volumes_lock);
+               err = -EBUSY;
+               goto out_free;
+       }
+       spin_unlock(&ubi->volumes_lock);
+
        /* Reserve physical eraseblocks */
        pebs = reserved_pebs - vol->reserved_pebs;
        if (pebs > 0) {
@@ -516,7 +553,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
 
        if (pebs < 0) {
                for (i = 0; i < -pebs; i++) {
-                       err = ubi_eba_unmap_leb(ubi, vol_id, reserved_pebs + i);
+                       err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
                        if (err)
                                goto out_acc;
                }
@@ -565,27 +602,28 @@ out_free:
 /**
  * ubi_add_volume - add volume.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  *
- * This function adds an existin volume and initializes all its data
- * structures. Returnes zero in case of success and a negative error code in
+ * This function adds an existing volume and initializes all its data
+ * structures. Returns zero in case of success and a negative error code in
  * case of failure.
  */
-int ubi_add_volume(struct ubi_device *ubi, int vol_id)
+int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
 {
-       int err;
-       struct ubi_volume *vol = ubi->volumes[vol_id];
+       int err, vol_id = vol->vol_id;
+       dev_t dev;
 
        dbg_msg("add volume %d", vol_id);
        ubi_dbg_dump_vol_info(vol);
-       ubi_assert(vol);
 
        /* Register character device for the volume */
        cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
        vol->cdev.owner = THIS_MODULE;
-       err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol->vol_id + 1), 1);
+       dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1);
+       err = cdev_add(&vol->cdev, dev, 1);
        if (err) {
-               ubi_err("cannot add character device for volume %d", vol_id);
+               ubi_err("cannot add character device for volume %d, error %d",
+                       vol_id, err);
                return err;
        }
 
@@ -595,7 +633,7 @@ int ubi_add_volume(struct ubi_device *ubi, int vol_id)
 
        vol->dev.release = vol_release;
        vol->dev.parent = &ubi->dev;
-       vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1);
+       vol->dev.devt = dev;
        vol->dev.class = ubi_class;
        sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
        err = device_register(&vol->dev);
@@ -623,22 +661,19 @@ out_cdev:
 /**
  * ubi_free_volume - free volume.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  *
- * This function frees all resources for volume @vol_id but does not remove it.
+ * This function frees all resources for volume @vol but does not remove it.
  * Used only when the UBI device is detached.
  */
-void ubi_free_volume(struct ubi_device *ubi, int vol_id)
+void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
 {
        int err;
-       struct ubi_volume *vol = ubi->volumes[vol_id];
 
-       dbg_msg("free volume %d", vol_id);
-       ubi_assert(vol);
+       dbg_msg("free volume %d", vol->vol_id);
 
-       vol->removed = 1;
+       ubi->volumes[vol->vol_id] = NULL;
        err = ubi_destroy_gluebi(vol);
-       ubi->volumes[vol_id] = NULL;
        cdev_del(&vol->cdev);
        volume_sysfs_close(vol);
 }
@@ -708,11 +743,6 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
                goto fail;
        }
 
-       if (vol->upd_marker != 0 && vol->upd_marker != 1) {
-               ubi_err("bad upd_marker");
-               goto fail;
-       }
-
        if (vol->upd_marker && vol->corrupted) {
                dbg_err("update marker and corrupted simultaneously");
                goto fail;
@@ -747,7 +777,7 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
 
        n = (long long)vol->used_ebs * vol->usable_leb_size;
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
-               if (vol->corrupted != 0) {
+               if (vol->corrupted) {
                        ubi_err("corrupted dynamic volume");
                        goto fail;
                }
@@ -764,10 +794,6 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
                        goto fail;
                }
        } else {
-               if (vol->corrupted != 0 && vol->corrupted != 1) {
-                       ubi_err("bad corrupted");
-                       goto fail;
-               }
                if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) {
                        ubi_err("bad used_ebs");
                        goto fail;
@@ -820,9 +846,7 @@ static void paranoid_check_volumes(struct ubi_device *ubi)
 {
        int i;
 
-       mutex_lock(&ubi->vtbl_mutex);
        for (i = 0; i < ubi->vtbl_slots; i++)
                paranoid_check_volume(ubi, i);
-       mutex_unlock(&ubi->vtbl_mutex);
 }
 #endif
index 25b3bd61c7ecfde59c0912d914ae92fbcdfc60b7..56fc3fbce838179b7d34276ccbb51e1ee2ff2018 100644 (file)
@@ -86,8 +86,10 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
 {
        int i, err;
        uint32_t crc;
+       struct ubi_volume *layout_vol;
 
        ubi_assert(idx >= 0 && idx < ubi->vtbl_slots);
+       layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
 
        if (!vtbl_rec)
                vtbl_rec = &empty_vtbl_record;
@@ -96,31 +98,25 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
                vtbl_rec->crc = cpu_to_be32(crc);
        }
 
-       mutex_lock(&ubi->vtbl_mutex);
        memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
        for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
-               err = ubi_eba_unmap_leb(ubi, UBI_LAYOUT_VOL_ID, i);
-               if (err) {
-                       mutex_unlock(&ubi->vtbl_mutex);
+               err = ubi_eba_unmap_leb(ubi, layout_vol, i);
+               if (err)
                        return err;
-               }
-               err = ubi_eba_write_leb(ubi, UBI_LAYOUT_VOL_ID, i, ubi->vtbl, 0,
+
+               err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
                                        ubi->vtbl_size, UBI_LONGTERM);
-               if (err) {
-                       mutex_unlock(&ubi->vtbl_mutex);
+               if (err)
                        return err;
-               }
        }
 
        paranoid_vtbl_check(ubi);
-       mutex_unlock(&ubi->vtbl_mutex);
-       return ubi_wl_flush(ubi);
+       return 0;
 }
 
 /**
- * vol_til_check - check if volume table is not corrupted and contains sensible
- * data.
- *
+ * vtbl_check - check if volume table is not corrupted and contains sensible
+ *              data.
  * @ubi: UBI device description object
  * @vtbl: volume table
  *
@@ -273,7 +269,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
         * this volume table copy was found during scanning. It has to be wiped
         * out.
         */
-       sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID);
+       sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
        if (sv)
                old_seb = ubi_scan_find_seb(sv, copy);
 
@@ -285,7 +281,7 @@ retry:
        }
 
        vid_hdr->vol_type = UBI_VID_DYNAMIC;
-       vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID);
+       vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID);
        vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
        vid_hdr->data_size = vid_hdr->used_ebs =
                             vid_hdr->data_pad = cpu_to_be32(0);
@@ -518,6 +514,17 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
                vol->name[vol->name_len] = '\0';
                vol->vol_id = i;
 
+               if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) {
+                       /* Auto re-size flag may be set only for one volume */
+                       if (ubi->autoresize_vol_id != -1) {
+                               ubi_err("more then one auto-resize volume (%d "
+                                       "and %d)", ubi->autoresize_vol_id, i);
+                               return -EINVAL;
+                       }
+
+                       ubi->autoresize_vol_id = i;
+               }
+
                ubi_assert(!ubi->volumes[i]);
                ubi->volumes[i] = vol;
                ubi->vol_count += 1;
@@ -568,6 +575,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
                vol->last_eb_bytes = sv->last_data_size;
        }
 
+       /* And add the layout volume */
        vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
        if (!vol)
                return -ENOMEM;
@@ -582,7 +590,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
        vol->last_eb_bytes = vol->reserved_pebs;
        vol->used_bytes =
                (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
-       vol->vol_id = UBI_LAYOUT_VOL_ID;
+       vol->vol_id = UBI_LAYOUT_VOLUME_ID;
+       vol->ref_count = 1;
 
        ubi_assert(!ubi->volumes[i]);
        ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol;
@@ -734,7 +743,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
        ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE;
        ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size);
 
-       sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID);
+       sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
        if (!sv) {
                /*
                 * No logical eraseblocks belonging to the layout volume were
index 6330c8cc72b5521fa8574d7f4d3f492b7e9cb231..a471a491f0ab0c2840543594966640487e7bacd4 100644 (file)
  */
 #define WL_MAX_FAILURES 32
 
-/**
- * struct ubi_wl_entry - wear-leveling entry.
- * @rb: link in the corresponding RB-tree
- * @ec: erase counter
- * @pnum: physical eraseblock number
- *
- * Each physical eraseblock has a corresponding &struct wl_entry object which
- * may be kept in different RB-trees.
- */
-struct ubi_wl_entry {
-       struct rb_node rb;
-       int ec;
-       int pnum;
-};
-
 /**
  * struct ubi_wl_prot_entry - PEB protection entry.
  * @rb_pnum: link in the @wl->prot.pnum RB-tree
@@ -216,9 +201,6 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
 #define paranoid_check_in_wl_tree(e, root)
 #endif
 
-/* Slab cache for wear-leveling entries */
-static struct kmem_cache *wl_entries_slab;
-
 /**
  * wl_tree_add - add a wear-leveling entry to a WL RB-tree.
  * @e: the wear-leveling entry to add
@@ -267,15 +249,26 @@ static int do_work(struct ubi_device *ubi)
        int err;
        struct ubi_work *wrk;
 
-       spin_lock(&ubi->wl_lock);
+       cond_resched();
 
+       /*
+        * @ubi->work_sem is used to synchronize with the workers. Workers take
+        * it in read mode, so many of them may be doing works at a time. But
+        * the queue flush code has to be sure the whole queue of works is
+        * done, and it takes the mutex in write mode.
+        */
+       down_read(&ubi->work_sem);
+       spin_lock(&ubi->wl_lock);
        if (list_empty(&ubi->works)) {
                spin_unlock(&ubi->wl_lock);
+               up_read(&ubi->work_sem);
                return 0;
        }
 
        wrk = list_entry(ubi->works.next, struct ubi_work, list);
        list_del(&wrk->list);
+       ubi->works_count -= 1;
+       ubi_assert(ubi->works_count >= 0);
        spin_unlock(&ubi->wl_lock);
 
        /*
@@ -286,11 +279,8 @@ static int do_work(struct ubi_device *ubi)
        err = wrk->func(ubi, wrk, 0);
        if (err)
                ubi_err("work failed with error code %d", err);
+       up_read(&ubi->work_sem);
 
-       spin_lock(&ubi->wl_lock);
-       ubi->works_count -= 1;
-       ubi_assert(ubi->works_count >= 0);
-       spin_unlock(&ubi->wl_lock);
        return err;
 }
 
@@ -549,8 +539,12 @@ retry:
  * prot_tree_del - remove a physical eraseblock from the protection trees
  * @ubi: UBI device description object
  * @pnum: the physical eraseblock to remove
+ *
+ * This function returns PEB @pnum from the protection trees and returns zero
+ * in case of success and %-ENODEV if the PEB was not found in the protection
+ * trees.
  */
-static void prot_tree_del(struct ubi_device *ubi, int pnum)
+static int prot_tree_del(struct ubi_device *ubi, int pnum)
 {
        struct rb_node *p;
        struct ubi_wl_prot_entry *pe = NULL;
@@ -561,7 +555,7 @@ static void prot_tree_del(struct ubi_device *ubi, int pnum)
                pe = rb_entry(p, struct ubi_wl_prot_entry, rb_pnum);
 
                if (pnum == pe->e->pnum)
-                       break;
+                       goto found;
 
                if (pnum < pe->e->pnum)
                        p = p->rb_left;
@@ -569,10 +563,14 @@ static void prot_tree_del(struct ubi_device *ubi, int pnum)
                        p = p->rb_right;
        }
 
+       return -ENODEV;
+
+found:
        ubi_assert(pe->e->pnum == pnum);
        rb_erase(&pe->rb_aec, &ubi->prot.aec);
        rb_erase(&pe->rb_pnum, &ubi->prot.pnum);
        kfree(pe);
+       return 0;
 }
 
 /**
@@ -744,7 +742,8 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
 static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                                int cancel)
 {
-       int err, put = 0;
+       int err, put = 0, scrubbing = 0, protect = 0;
+       struct ubi_wl_prot_entry *uninitialized_var(pe);
        struct ubi_wl_entry *e1, *e2;
        struct ubi_vid_hdr *vid_hdr;
 
@@ -757,21 +756,17 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
        if (!vid_hdr)
                return -ENOMEM;
 
+       mutex_lock(&ubi->move_mutex);
        spin_lock(&ubi->wl_lock);
+       ubi_assert(!ubi->move_from && !ubi->move_to);
+       ubi_assert(!ubi->move_to_put);
 
-       /*
-        * Only one WL worker at a time is supported at this implementation, so
-        * make sure a PEB is not being moved already.
-        */
-       if (ubi->move_to || !ubi->free.rb_node ||
+       if (!ubi->free.rb_node ||
            (!ubi->used.rb_node && !ubi->scrub.rb_node)) {
                /*
-                * Only one WL worker at a time is supported at this
-                * implementation, so if a LEB is already being moved, cancel.
-                *
-                * No free physical eraseblocks? Well, we cancel wear-leveling
-                * then. It will be triggered again when a free physical
-                * eraseblock appears.
+                * No free physical eraseblocks? Well, they must be waiting in
+                * the queue to be erased. Cancel movement - it will be
+                * triggered again when a free physical eraseblock appears.
                 *
                 * No used physical eraseblocks? They must be temporarily
                 * protected from being moved. They will be moved to the
@@ -780,10 +775,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                 */
                dbg_wl("cancel WL, a list is empty: free %d, used %d",
                       !ubi->free.rb_node, !ubi->used.rb_node);
-               ubi->wl_scheduled = 0;
-               spin_unlock(&ubi->wl_lock);
-               ubi_free_vid_hdr(ubi, vid_hdr);
-               return 0;
+               goto out_cancel;
        }
 
        if (!ubi->scrub.rb_node) {
@@ -798,27 +790,24 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) {
                        dbg_wl("no WL needed: min used EC %d, max free EC %d",
                               e1->ec, e2->ec);
-                       ubi->wl_scheduled = 0;
-                       spin_unlock(&ubi->wl_lock);
-                       ubi_free_vid_hdr(ubi, vid_hdr);
-                       return 0;
+                       goto out_cancel;
                }
                paranoid_check_in_wl_tree(e1, &ubi->used);
                rb_erase(&e1->rb, &ubi->used);
                dbg_wl("move PEB %d EC %d to PEB %d EC %d",
                       e1->pnum, e1->ec, e2->pnum, e2->ec);
        } else {
+               /* Perform scrubbing */
+               scrubbing = 1;
                e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb);
                e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
                paranoid_check_in_wl_tree(e1, &ubi->scrub);
-       rb_erase(&e1->rb, &ubi->scrub);
+               rb_erase(&e1->rb, &ubi->scrub);
                dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
        }
 
        paranoid_check_in_wl_tree(e2, &ubi->free);
        rb_erase(&e2->rb, &ubi->free);
-       ubi_assert(!ubi->move_from && !ubi->move_to);
-       ubi_assert(!ubi->move_to_put && !ubi->move_from_put);
        ubi->move_from = e1;
        ubi->move_to = e2;
        spin_unlock(&ubi->wl_lock);
@@ -828,6 +817,10 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
         * We so far do not know which logical eraseblock our physical
         * eraseblock (@e1) belongs to. We have to read the volume identifier
         * header first.
+        *
+        * Note, we are protected from this PEB being unmapped and erased. The
+        * 'ubi_wl_put_peb()' would wait for moving to be finished if the PEB
+        * which is being moved was unmapped.
         */
 
        err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0);
@@ -842,32 +835,51 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                         * likely have the VID header in place.
                         */
                        dbg_wl("PEB %d has no VID header", e1->pnum);
-                       err = 0;
-               } else {
-                       ubi_err("error %d while reading VID header from PEB %d",
-                               err, e1->pnum);
-                       if (err > 0)
-                               err = -EIO;
+                       goto out_not_moved;
                }
-               goto error;
+
+               ubi_err("error %d while reading VID header from PEB %d",
+                       err, e1->pnum);
+               if (err > 0)
+                       err = -EIO;
+               goto out_error;
        }
 
        err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr);
        if (err) {
-               if (err == UBI_IO_BITFLIPS)
-                       err = 0;
-               goto error;
+
+               if (err < 0)
+                       goto out_error;
+               if (err == 1)
+                       goto out_not_moved;
+
+               /*
+                * For some reason the LEB was not moved - it might be because
+                * the volume is being deleted. We should prevent this PEB from
+                * being selected for wear-levelling movement for some "time",
+                * so put it to the protection tree.
+                */
+
+               dbg_wl("cancelled moving PEB %d", e1->pnum);
+               pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS);
+               if (!pe) {
+                       err = -ENOMEM;
+                       goto out_error;
+               }
+
+               protect = 1;
        }
 
        ubi_free_vid_hdr(ubi, vid_hdr);
        spin_lock(&ubi->wl_lock);
+       if (protect)
+               prot_tree_add(ubi, e1, pe, protect);
        if (!ubi->move_to_put)
                wl_tree_add(e2, &ubi->used);
        else
                put = 1;
        ubi->move_from = ubi->move_to = NULL;
-       ubi->move_from_put = ubi->move_to_put = 0;
-       ubi->wl_scheduled = 0;
+       ubi->move_to_put = ubi->wl_scheduled = 0;
        spin_unlock(&ubi->wl_lock);
 
        if (put) {
@@ -877,62 +889,67 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                 */
                dbg_wl("PEB %d was put meanwhile, erase", e2->pnum);
                err = schedule_erase(ubi, e2, 0);
-               if (err) {
-                       kmem_cache_free(wl_entries_slab, e2);
-                       ubi_ro_mode(ubi);
-               }
+               if (err)
+                       goto out_error;
        }
 
-       err = schedule_erase(ubi, e1, 0);
-       if (err) {
-               kmem_cache_free(wl_entries_slab, e1);
-               ubi_ro_mode(ubi);
+       if (!protect) {
+               err = schedule_erase(ubi, e1, 0);
+               if (err)
+                       goto out_error;
        }
 
+
        dbg_wl("done");
-       return err;
+       mutex_unlock(&ubi->move_mutex);
+       return 0;
 
        /*
-        * Some error occurred. @e1 was not changed, so return it back. @e2
-        * might be changed, schedule it for erasure.
+        * For some reasons the LEB was not moved, might be an error, might be
+        * something else. @e1 was not changed, so return it back. @e2 might
+        * be changed, schedule it for erasure.
         */
-error:
-       if (err)
-               dbg_wl("error %d occurred, cancel operation", err);
-       ubi_assert(err <= 0);
-
+out_not_moved:
        ubi_free_vid_hdr(ubi, vid_hdr);
        spin_lock(&ubi->wl_lock);
-       ubi->wl_scheduled = 0;
-       if (ubi->move_from_put)
-               put = 1;
+       if (scrubbing)
+               wl_tree_add(e1, &ubi->scrub);
        else
                wl_tree_add(e1, &ubi->used);
        ubi->move_from = ubi->move_to = NULL;
-       ubi->move_from_put = ubi->move_to_put = 0;
+       ubi->move_to_put = ubi->wl_scheduled = 0;
        spin_unlock(&ubi->wl_lock);
 
-       if (put) {
-               /*
-                * Well, the target PEB was put meanwhile, schedule it for
-                * erasure.
-                */
-               dbg_wl("PEB %d was put meanwhile, erase", e1->pnum);
-               err = schedule_erase(ubi, e1, 0);
-               if (err) {
-                       kmem_cache_free(wl_entries_slab, e1);
-                       ubi_ro_mode(ubi);
-               }
-       }
-
        err = schedule_erase(ubi, e2, 0);
-       if (err) {
-               kmem_cache_free(wl_entries_slab, e2);
-               ubi_ro_mode(ubi);
-       }
+       if (err)
+               goto out_error;
+
+       mutex_unlock(&ubi->move_mutex);
+       return 0;
+
+out_error:
+       ubi_err("error %d while moving PEB %d to PEB %d",
+               err, e1->pnum, e2->pnum);
 
-       yield();
+       ubi_free_vid_hdr(ubi, vid_hdr);
+       spin_lock(&ubi->wl_lock);
+       ubi->move_from = ubi->move_to = NULL;
+       ubi->move_to_put = ubi->wl_scheduled = 0;
+       spin_unlock(&ubi->wl_lock);
+
+       kmem_cache_free(ubi_wl_entry_slab, e1);
+       kmem_cache_free(ubi_wl_entry_slab, e2);
+       ubi_ro_mode(ubi);
+
+       mutex_unlock(&ubi->move_mutex);
        return err;
+
+out_cancel:
+       ubi->wl_scheduled = 0;
+       spin_unlock(&ubi->wl_lock);
+       mutex_unlock(&ubi->move_mutex);
+       ubi_free_vid_hdr(ubi, vid_hdr);
+       return 0;
 }
 
 /**
@@ -1020,7 +1037,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
        if (cancel) {
                dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
                kfree(wl_wrk);
-               kmem_cache_free(wl_entries_slab, e);
+               kmem_cache_free(ubi_wl_entry_slab, e);
                return 0;
        }
 
@@ -1049,7 +1066,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
 
        ubi_err("failed to erase PEB %d, error %d", pnum, err);
        kfree(wl_wrk);
-       kmem_cache_free(wl_entries_slab, e);
+       kmem_cache_free(ubi_wl_entry_slab, e);
 
        if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
            err == -EBUSY) {
@@ -1119,8 +1136,7 @@ out_ro:
 }
 
 /**
- * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling
- * unit.
+ * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling unit.
  * @ubi: UBI device description object
  * @pnum: physical eraseblock to return
  * @torture: if this physical eraseblock has to be tortured
@@ -1128,7 +1144,7 @@ out_ro:
  * This function is called to return physical eraseblock @pnum to the pool of
  * free physical eraseblocks. The @torture flag has to be set if an I/O error
  * occurred to this @pnum and it has to be tested. This function returns zero
- * in case of success and a negative error code in case of failure.
+ * in case of success, and a negative error code in case of failure.
  */
 int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
 {
@@ -1139,8 +1155,8 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
        ubi_assert(pnum >= 0);
        ubi_assert(pnum < ubi->peb_count);
 
+retry:
        spin_lock(&ubi->wl_lock);
-
        e = ubi->lookuptbl[pnum];
        if (e == ubi->move_from) {
                /*
@@ -1148,17 +1164,22 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
                 * be moved. It will be scheduled for erasure in the
                 * wear-leveling worker.
                 */
-               dbg_wl("PEB %d is being moved", pnum);
-               ubi_assert(!ubi->move_from_put);
-               ubi->move_from_put = 1;
+               dbg_wl("PEB %d is being moved, wait", pnum);
                spin_unlock(&ubi->wl_lock);
-               return 0;
+
+               /* Wait for the WL worker by taking the @ubi->move_mutex */
+               mutex_lock(&ubi->move_mutex);
+               mutex_unlock(&ubi->move_mutex);
+               goto retry;
        } else if (e == ubi->move_to) {
                /*
                 * User is putting the physical eraseblock which was selected
                 * as the target the data is moved to. It may happen if the EBA
-                * unit already re-mapped the LEB but the WL unit did has not
-                * put the PEB to the "used" tree.
+                * unit already re-mapped the LEB in 'ubi_eba_copy_leb()' but
+                * the WL unit has not put the PEB to the "used" tree yet, but
+                * it is about to do this. So we just set a flag which will
+                * tell the WL worker that the PEB is not needed anymore and
+                * should be scheduled for erasure.
                 */
                dbg_wl("PEB %d is the target of data moving", pnum);
                ubi_assert(!ubi->move_to_put);
@@ -1172,8 +1193,15 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
                } else if (in_wl_tree(e, &ubi->scrub)) {
                        paranoid_check_in_wl_tree(e, &ubi->scrub);
                        rb_erase(&e->rb, &ubi->scrub);
-               } else
-                       prot_tree_del(ubi, e->pnum);
+               } else {
+                       err = prot_tree_del(ubi, e->pnum);
+                       if (err) {
+                               ubi_err("PEB %d not found", pnum);
+                               ubi_ro_mode(ubi);
+                               spin_unlock(&ubi->wl_lock);
+                               return err;
+                       }
+               }
        }
        spin_unlock(&ubi->wl_lock);
 
@@ -1227,8 +1255,17 @@ retry:
        if (in_wl_tree(e, &ubi->used)) {
                paranoid_check_in_wl_tree(e, &ubi->used);
                rb_erase(&e->rb, &ubi->used);
-       } else
-               prot_tree_del(ubi, pnum);
+       } else {
+               int err;
+
+               err = prot_tree_del(ubi, e->pnum);
+               if (err) {
+                       ubi_err("PEB %d not found", pnum);
+                       ubi_ro_mode(ubi);
+                       spin_unlock(&ubi->wl_lock);
+                       return err;
+               }
+       }
 
        wl_tree_add(e, &ubi->scrub);
        spin_unlock(&ubi->wl_lock);
@@ -1249,17 +1286,32 @@ retry:
  */
 int ubi_wl_flush(struct ubi_device *ubi)
 {
-       int err, pending_count;
-
-       pending_count = ubi->works_count;
-
-       dbg_wl("flush (%d pending works)", pending_count);
+       int err;
 
        /*
         * Erase while the pending works queue is not empty, but not more then
         * the number of currently pending works.
         */
-       while (pending_count-- > 0) {
+       dbg_wl("flush (%d pending works)", ubi->works_count);
+       while (ubi->works_count) {
+               err = do_work(ubi);
+               if (err)
+                       return err;
+       }
+
+       /*
+        * Make sure all the works which have been done in parallel are
+        * finished.
+        */
+       down_write(&ubi->work_sem);
+       up_write(&ubi->work_sem);
+
+       /*
+        * And in case last was the WL worker and it cancelled the LEB
+        * movement, flush again.
+        */
+       while (ubi->works_count) {
+               dbg_wl("flush more (%d pending works)", ubi->works_count);
                err = do_work(ubi);
                if (err)
                        return err;
@@ -1294,7 +1346,7 @@ static void tree_destroy(struct rb_root *root)
                                        rb->rb_right = NULL;
                        }
 
-                       kmem_cache_free(wl_entries_slab, e);
+                       kmem_cache_free(ubi_wl_entry_slab, e);
                }
        }
 }
@@ -1303,7 +1355,7 @@ static void tree_destroy(struct rb_root *root)
  * ubi_thread - UBI background thread.
  * @u: the UBI device description object pointer
  */
-static int ubi_thread(void *u)
+int ubi_thread(void *u)
 {
        int failures = 0;
        struct ubi_device *ubi = u;
@@ -1394,36 +1446,22 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
        ubi->used = ubi->free = ubi->scrub = RB_ROOT;
        ubi->prot.pnum = ubi->prot.aec = RB_ROOT;
        spin_lock_init(&ubi->wl_lock);
+       mutex_init(&ubi->move_mutex);
+       init_rwsem(&ubi->work_sem);
        ubi->max_ec = si->max_ec;
        INIT_LIST_HEAD(&ubi->works);
 
        sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num);
 
-       ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
-       if (IS_ERR(ubi->bgt_thread)) {
-               err = PTR_ERR(ubi->bgt_thread);
-               ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
-                       err);
-               return err;
-       }
-
-       if (ubi_devices_cnt == 0) {
-               wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab",
-                                                   sizeof(struct ubi_wl_entry),
-                                                   0, 0, NULL);
-               if (!wl_entries_slab)
-                       return -ENOMEM;
-       }
-
        err = -ENOMEM;
        ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL);
        if (!ubi->lookuptbl)
-               goto out_free;
+               return err;
 
        list_for_each_entry_safe(seb, tmp, &si->erase, u.list) {
                cond_resched();
 
-               e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL);
+               e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
                if (!e)
                        goto out_free;
 
@@ -1431,7 +1469,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                e->ec = seb->ec;
                ubi->lookuptbl[e->pnum] = e;
                if (schedule_erase(ubi, e, 0)) {
-                       kmem_cache_free(wl_entries_slab, e);
+                       kmem_cache_free(ubi_wl_entry_slab, e);
                        goto out_free;
                }
        }
@@ -1439,7 +1477,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
        list_for_each_entry(seb, &si->free, u.list) {
                cond_resched();
 
-               e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL);
+               e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
                if (!e)
                        goto out_free;
 
@@ -1453,7 +1491,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
        list_for_each_entry(seb, &si->corr, u.list) {
                cond_resched();
 
-               e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL);
+               e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
                if (!e)
                        goto out_free;
 
@@ -1461,7 +1499,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                e->ec = seb->ec;
                ubi->lookuptbl[e->pnum] = e;
                if (schedule_erase(ubi, e, 0)) {
-                       kmem_cache_free(wl_entries_slab, e);
+                       kmem_cache_free(ubi_wl_entry_slab, e);
                        goto out_free;
                }
        }
@@ -1470,7 +1508,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
                        cond_resched();
 
-                       e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL);
+                       e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
                        if (!e)
                                goto out_free;
 
@@ -1510,8 +1548,6 @@ out_free:
        tree_destroy(&ubi->free);
        tree_destroy(&ubi->scrub);
        kfree(ubi->lookuptbl);
-       if (ubi_devices_cnt == 0)
-               kmem_cache_destroy(wl_entries_slab);
        return err;
 }
 
@@ -1541,7 +1577,7 @@ static void protection_trees_destroy(struct ubi_device *ubi)
                                        rb->rb_right = NULL;
                        }
 
-                       kmem_cache_free(wl_entries_slab, pe->e);
+                       kmem_cache_free(ubi_wl_entry_slab, pe->e);
                        kfree(pe);
                }
        }
@@ -1553,10 +1589,6 @@ static void protection_trees_destroy(struct ubi_device *ubi)
  */
 void ubi_wl_close(struct ubi_device *ubi)
 {
-       dbg_wl("disable \"%s\"", ubi->bgt_name);
-       if (ubi->bgt_thread)
-               kthread_stop(ubi->bgt_thread);
-
        dbg_wl("close the UBI wear-leveling unit");
 
        cancel_pending(ubi);
@@ -1565,8 +1597,6 @@ void ubi_wl_close(struct ubi_device *ubi)
        tree_destroy(&ubi->free);
        tree_destroy(&ubi->scrub);
        kfree(ubi->lookuptbl);
-       if (ubi_devices_cnt == 1)
-               kmem_cache_destroy(wl_entries_slab);
 }
 
 #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
index 7d170cd381c39191d7d9bfae65b296026de49934..9cc25fd80b605c742411b3042c27808976199453 100644 (file)
@@ -1737,10 +1737,8 @@ config SC92031
 
 config CPMAC
        tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
-       depends on NET_ETHERNET && EXPERIMENTAL && AR7
+       depends on NET_ETHERNET && EXPERIMENTAL && AR7 && BROKEN
        select PHYLIB
-       select FIXED_PHY
-       select FIXED_MII_100_FDX
        help
          TI AR7 CPMAC Ethernet support
 
index 6ccebb830ff90bc86f4b00ed0f622f8fe0c0245b..c85194f2cd2dc2b8a9bf5628e63b9189db0ec2cd 100644 (file)
@@ -845,15 +845,6 @@ static void cpmac_adjust_link(struct net_device *dev)
        spin_unlock(&priv->lock);
 }
 
-static int cpmac_link_update(struct net_device *dev,
-                            struct fixed_phy_status *status)
-{
-       status->link = 1;
-       status->speed = 100;
-       status->duplex = 1;
-       return 0;
-}
-
 static int cpmac_open(struct net_device *dev)
 {
        int i, size, res;
@@ -996,11 +987,11 @@ static int external_switch;
 static int __devinit cpmac_probe(struct platform_device *pdev)
 {
        int rc, phy_id, i;
+       int mdio_bus_id = cpmac_mii.id;
        struct resource *mem;
        struct cpmac_priv *priv;
        struct net_device *dev;
        struct plat_cpmac_data *pdata;
-       struct fixed_info *fixed_phy;
        DECLARE_MAC_BUF(mac);
 
        pdata = pdev->dev.platform_data;
@@ -1014,9 +1005,23 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
        }
 
        if (phy_id == PHY_MAX_ADDR) {
-               if (external_switch || dumb_switch)
+               if (external_switch || dumb_switch) {
+                       struct fixed_phy_status status = {};
+
+                       mdio_bus_id = 0;
+
+                       /*
+                        * FIXME: this should be in the platform code!
+                        * Since there is not platform code at all (that is,
+                        * no mainline users of that driver), place it here
+                        * for now.
+                        */
                        phy_id = 0;
-               else {
+                       status.link = 1;
+                       status.duplex = 1;
+                       status.speed = 100;
+                       fixed_phy_add(PHY_POLL, phy_id, &status);
+               } else {
                        printk(KERN_ERR "cpmac: no PHY present\n");
                        return -ENODEV;
                }
@@ -1060,32 +1065,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
        priv->msg_enable = netif_msg_init(debug_level, 0xff);
        memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
 
-       if (phy_id == 31) {
-               snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, cpmac_mii.id,
-                        phy_id);
-       } else {
-               /* Let's try to get a free fixed phy... */
-               for (i = 0; i < MAX_PHY_AMNT; i++) {
-                       fixed_phy = fixed_mdio_get_phydev(i);
-                       if (!fixed_phy)
-                               continue;
-                       if (!fixed_phy->phydev->attached_dev) {
-                               strncpy(priv->phy_name,
-                                       fixed_phy->phydev->dev.bus_id,
-                                       BUS_ID_SIZE);
-                               fixed_mdio_set_link_update(fixed_phy->phydev,
-                                                          &cpmac_link_update);
-                               goto phy_found;
-                       }
-               }
-               if (netif_msg_drv(priv))
-                       printk(KERN_ERR "%s: Could not find fixed PHY\n",
-                              dev->name);
-               rc = -ENODEV;
-               goto fail;
-       }
+       snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
 
-phy_found:
        priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0,
                                PHY_INTERFACE_MODE_MII);
        if (IS_ERR(priv->phy)) {
index 0908335892dbba7214fc1d995d7a9af2da7f54e5..0aac1ff511df768a6ea38175e22a270a00ebaf20 100644 (file)
@@ -147,12 +147,12 @@ static void b43_map_led(struct b43_wldev *dev,
        case B43_LED_TRANSFER:
        case B43_LED_APTRANSFER:
                snprintf(name, sizeof(name),
-                        "b43-%s:tx", wiphy_name(hw->wiphy));
+                        "b43-%s::tx", wiphy_name(hw->wiphy));
                b43_register_led(dev, &dev->led_tx, name,
                                 ieee80211_get_tx_led_name(hw),
                                 led_index, activelow);
                snprintf(name, sizeof(name),
-                        "b43-%s:rx", wiphy_name(hw->wiphy));
+                        "b43-%s::rx", wiphy_name(hw->wiphy));
                b43_register_led(dev, &dev->led_rx, name,
                                 ieee80211_get_rx_led_name(hw),
                                 led_index, activelow);
@@ -162,7 +162,7 @@ static void b43_map_led(struct b43_wldev *dev,
        case B43_LED_RADIO_B:
        case B43_LED_MODE_BG:
                snprintf(name, sizeof(name),
-                        "b43-%s:radio", wiphy_name(hw->wiphy));
+                        "b43-%s::radio", wiphy_name(hw->wiphy));
                b43_register_led(dev, &dev->led_radio, name,
                                 b43_rfkill_led_name(dev),
                                 led_index, activelow);
@@ -173,7 +173,7 @@ static void b43_map_led(struct b43_wldev *dev,
        case B43_LED_WEIRD:
        case B43_LED_ASSOC:
                snprintf(name, sizeof(name),
-                        "b43-%s:assoc", wiphy_name(hw->wiphy));
+                        "b43-%s::assoc", wiphy_name(hw->wiphy));
                b43_register_led(dev, &dev->led_assoc, name,
                                 ieee80211_get_assoc_led_name(hw),
                                 led_index, activelow);
index b306fef1ac4151dffe03a89d4328ca4e6f703547..80c9deca5f35aa3313245d099215d5f387c687b1 100644 (file)
@@ -137,6 +137,31 @@ struct device_node *of_get_parent(const struct device_node *node)
 }
 EXPORT_SYMBOL(of_get_parent);
 
+/**
+ *     of_get_next_parent - Iterate to a node's parent
+ *     @node:  Node to get parent of
+ *
+ *     This is like of_get_parent() except that it drops the
+ *     refcount on the passed node, making it suitable for iterating
+ *     through a node's parents.
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_get_next_parent(struct device_node *node)
+{
+       struct device_node *parent;
+
+       if (!node)
+               return NULL;
+
+       read_lock(&devtree_lock);
+       parent = of_node_get(node->parent);
+       of_node_put(node);
+       read_unlock(&devtree_lock);
+       return parent;
+}
+
 /**
  *     of_get_next_child - Iterate a node childs
  *     @node:  parent node
index b47bb2d7476a82e5618fc50c0772cfea9ddd46ec..ca09a63a64db7bdf66a03f0da0069518615e3d6f 100644 (file)
@@ -85,6 +85,15 @@ static int of_platform_device_resume(struct device * dev)
        return error;
 }
 
+static void of_platform_device_shutdown(struct device *dev)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+       if (dev->driver && drv->shutdown)
+               drv->shutdown(of_dev);
+}
+
 int of_bus_type_init(struct bus_type *bus, const char *name)
 {
        bus->name = name;
@@ -93,6 +102,7 @@ int of_bus_type_init(struct bus_type *bus, const char *name)
        bus->remove = of_platform_device_remove;
        bus->suspend = of_platform_device_suspend;
        bus->resume = of_platform_device_resume;
+       bus->shutdown = of_platform_device_shutdown;
        return bus_register(bus);
 }
 
index dada89906314c7103b89b6e96a071afe3900d74d..662b4c279cfcaff775739eb3e35f128bc065c12c 100644 (file)
@@ -183,7 +183,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
        if (ACPI_SUCCESS(status))
                dev->capabilities |= PNP_CONFIGURABLE;
        dev->capabilities |= PNP_READ;
-       if (device->flags.dynamic_status)
+       if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE))
                dev->capabilities |= PNP_WRITE;
        if (device->flags.removable)
                dev->capabilities |= PNP_REMOVABLE;
index d4824840c5bfc9c8bb877399014e01305adf3862..c444d6b10c581e9cb26ad9d110e6a3f34be35757 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),
@@ -116,6 +115,7 @@ static struct device_attribute power_supply_attrs[] = {
        /* Properties of type `const char *' */
        POWER_SUPPLY_ATTR(model_name),
        POWER_SUPPLY_ATTR(manufacturer),
+       POWER_SUPPLY_ATTR(serial_number),
 };
 
 static ssize_t power_supply_show_static_attrs(struct device *dev,
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 6a44fb1dc167c0c74a39ac161f287e68c64e212f..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.
 
@@ -1138,17 +1142,17 @@ config SERIAL_SGI_L1_CONSOLE
                say Y.  Otherwise, say N.
 
 config SERIAL_MPC52xx
-       tristate "Freescale MPC52xx family PSC serial support"
-       depends on PPC_MPC52xx
+       tristate "Freescale MPC52xx/MPC512x family PSC serial support"
+       depends on PPC_MPC52xx || PPC_MPC512x
        select SERIAL_CORE
        help
-         This drivers support the MPC52xx PSC serial ports. If you would
-         like to use them, you must answer Y or M to this option. Not that
+         This driver supports MPC52xx and MPC512x PSC serial ports. If you would
+         like to use them, you must answer Y or M to this option. Note that
          for use as console, it must be included in kernel and not as a
          module.
 
 config SERIAL_MPC52xx_CONSOLE
-       bool "Console on a Freescale MPC52xx family PSC serial port"
+       bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port"
        depends on SERIAL_MPC52xx=y
        select SERIAL_CORE_CONSOLE
        help
@@ -1156,7 +1160,7 @@ config SERIAL_MPC52xx_CONSOLE
          of the Freescale MPC52xx family as a console.
 
 config SERIAL_MPC52xx_CONSOLE_BAUD
-       int "Freescale MPC52xx family PSC serial port baud"
+       int "Freescale MPC52xx/MPC512x family PSC serial port baud"
        depends on SERIAL_MPC52xx_CONSOLE=y
        default "9600"
        help
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 bbae5a220219836658d3c52ff8460591a855ed62..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 = 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 3c4d29e59b2c58581d1b380e95fabff4f5e9a6df..a638f23c6c6110189e25284f148c1e9671ec8535 100644 (file)
@@ -16,6 +16,9 @@
  * Some of the code has been inspired/copied from the 2.4 code written
  * by Dale Farnsworth <dfarnsworth@mvista.com>.
  *
+ * Copyright (C) 2008 Freescale Semiconductor Inc.
+ *                    John Rigby <jrigby@gmail.com>
+ * Added support for MPC5121
  * Copyright (C) 2006 Secret Lab Technologies Ltd.
  *                    Grant Likely <grant.likely@secretlab.ca>
  * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
@@ -67,7 +70,6 @@
 #include <linux/serial.h>
 #include <linux/sysrq.h>
 #include <linux/console.h>
-
 #include <linux/delay.h>
 #include <linux/io.h>
 
@@ -79,6 +81,7 @@
 #endif
 
 #include <asm/mpc52xx.h>
+#include <asm/mpc512x.h>
 #include <asm/mpc52xx_psc.h>
 
 #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -111,8 +114,8 @@ static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
 static void mpc52xx_uart_of_enumerate(void);
 #endif
 
+
 #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
-#define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
 
 
 /* Forward declaration of the interruption handling routine */
@@ -128,15 +131,301 @@ static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
 #define uart_console(port)     (0)
 #endif
 
+/* ======================================================================== */
+/* PSC fifo operations for isolating differences between 52xx and 512x      */
+/* ======================================================================== */
+
+struct psc_ops {
+       void            (*fifo_init)(struct uart_port *port);
+       int             (*raw_rx_rdy)(struct uart_port *port);
+       int             (*raw_tx_rdy)(struct uart_port *port);
+       int             (*rx_rdy)(struct uart_port *port);
+       int             (*tx_rdy)(struct uart_port *port);
+       int             (*tx_empty)(struct uart_port *port);
+       void            (*stop_rx)(struct uart_port *port);
+       void            (*start_tx)(struct uart_port *port);
+       void            (*stop_tx)(struct uart_port *port);
+       void            (*rx_clr_irq)(struct uart_port *port);
+       void            (*tx_clr_irq)(struct uart_port *port);
+       void            (*write_char)(struct uart_port *port, unsigned char c);
+       unsigned char   (*read_char)(struct uart_port *port);
+       void            (*cw_disable_ints)(struct uart_port *port);
+       void            (*cw_restore_ints)(struct uart_port *port);
+       unsigned long   (*getuartclk)(void *p);
+};
+
+#ifdef CONFIG_PPC_MPC52xx
+#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
+static void mpc52xx_psc_fifo_init(struct uart_port *port)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+       struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
+
+       /* /32 prescaler */
+       out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
+
+       out_8(&fifo->rfcntl, 0x00);
+       out_be16(&fifo->rfalarm, 0x1ff);
+       out_8(&fifo->tfcntl, 0x07);
+       out_be16(&fifo->tfalarm, 0x80);
+
+       port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_status)
+           & MPC52xx_PSC_SR_RXRDY;
+}
+
+static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_status)
+           & MPC52xx_PSC_SR_TXRDY;
+}
+
+
+static int mpc52xx_psc_rx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_isr)
+           & port->read_status_mask
+           & MPC52xx_PSC_IMR_RXRDY;
+}
+
+static int mpc52xx_psc_tx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_isr)
+           & port->read_status_mask
+           & MPC52xx_PSC_IMR_TXRDY;
+}
+
+static int mpc52xx_psc_tx_empty(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_status)
+           & MPC52xx_PSC_SR_TXEMP;
+}
+
+static void mpc52xx_psc_start_tx(struct uart_port *port)
+{
+       port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_stop_tx(struct uart_port *port)
+{
+       port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_stop_rx(struct uart_port *port)
+{
+       port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_rx_clr_irq(struct uart_port *port)
+{
+}
+
+static void mpc52xx_psc_tx_clr_irq(struct uart_port *port)
+{
+}
+
+static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c)
+{
+       out_8(&PSC(port)->mpc52xx_psc_buffer_8, c);
+}
+
+static unsigned char mpc52xx_psc_read_char(struct uart_port *port)
+{
+       return in_8(&PSC(port)->mpc52xx_psc_buffer_8);
+}
+
+static void mpc52xx_psc_cw_disable_ints(struct uart_port *port)
+{
+       out_be16(&PSC(port)->mpc52xx_psc_imr, 0);
+}
+
+static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
+{
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+/* Search for bus-frequency property in this node or a parent */
+static unsigned long mpc52xx_getuartclk(void *p)
+{
 #if defined(CONFIG_PPC_MERGE)
-static struct of_device_id mpc52xx_uart_of_match[] = {
-       { .type = "serial", .compatible = "fsl,mpc5200-psc-uart", },
-       { .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */
-       { .type = "serial", .compatible = "mpc5200-serial", }, /* efika */
-       {},
+       /*
+        * 5200 UARTs have a / 32 prescaler
+        * but the generic serial code assumes 16
+        * so return ipb freq / 2
+        */
+       return mpc52xx_find_ipb_freq(p) / 2;
+#else
+       pr_debug("unexpected call to mpc52xx_getuartclk with arch/ppc\n");
+       return NULL;
+#endif
+}
+
+static struct psc_ops mpc52xx_psc_ops = {
+       .fifo_init = mpc52xx_psc_fifo_init,
+       .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
+       .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
+       .rx_rdy = mpc52xx_psc_rx_rdy,
+       .tx_rdy = mpc52xx_psc_tx_rdy,
+       .tx_empty = mpc52xx_psc_tx_empty,
+       .stop_rx = mpc52xx_psc_stop_rx,
+       .start_tx = mpc52xx_psc_start_tx,
+       .stop_tx = mpc52xx_psc_stop_tx,
+       .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
+       .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
+       .write_char = mpc52xx_psc_write_char,
+       .read_char = mpc52xx_psc_read_char,
+       .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
+       .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
+       .getuartclk = mpc52xx_getuartclk,
+};
+
+#endif /* CONFIG_MPC52xx */
+
+#ifdef CONFIG_PPC_MPC512x
+#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
+static void mpc512x_psc_fifo_init(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+       out_be32(&FIFO_512x(port)->txalarm, 1);
+       out_be32(&FIFO_512x(port)->tximr, 0);
+
+       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+       out_be32(&FIFO_512x(port)->rxalarm, 1);
+       out_be32(&FIFO_512x(port)->rximr, 0);
+
+       out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM);
+       out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM);
+}
+
+static int mpc512x_psc_raw_rx_rdy(struct uart_port *port)
+{
+       return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY);
+}
+
+static int mpc512x_psc_raw_tx_rdy(struct uart_port *port)
+{
+       return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL);
+}
+
+static int mpc512x_psc_rx_rdy(struct uart_port *port)
+{
+       return in_be32(&FIFO_512x(port)->rxsr)
+           & in_be32(&FIFO_512x(port)->rximr)
+           & MPC512x_PSC_FIFO_ALARM;
+}
+
+static int mpc512x_psc_tx_rdy(struct uart_port *port)
+{
+       return in_be32(&FIFO_512x(port)->txsr)
+           & in_be32(&FIFO_512x(port)->tximr)
+           & MPC512x_PSC_FIFO_ALARM;
+}
+
+static int mpc512x_psc_tx_empty(struct uart_port *port)
+{
+       return in_be32(&FIFO_512x(port)->txsr)
+           & MPC512x_PSC_FIFO_EMPTY;
+}
+
+static void mpc512x_psc_stop_rx(struct uart_port *port)
+{
+       unsigned long rx_fifo_imr;
+
+       rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr);
+       rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+       out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr);
+}
+
+static void mpc512x_psc_start_tx(struct uart_port *port)
+{
+       unsigned long tx_fifo_imr;
+
+       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
+       tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
+       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc512x_psc_stop_tx(struct uart_port *port)
+{
+       unsigned long tx_fifo_imr;
+
+       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
+       tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc512x_psc_rx_clr_irq(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr));
+}
+
+static void mpc512x_psc_tx_clr_irq(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr));
+}
+
+static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c)
+{
+       out_8(&FIFO_512x(port)->txdata_8, c);
+}
+
+static unsigned char mpc512x_psc_read_char(struct uart_port *port)
+{
+       return in_8(&FIFO_512x(port)->rxdata_8);
+}
+
+static void mpc512x_psc_cw_disable_ints(struct uart_port *port)
+{
+       port->read_status_mask =
+               in_be32(&FIFO_512x(port)->tximr) << 16 |
+               in_be32(&FIFO_512x(port)->rximr);
+       out_be32(&FIFO_512x(port)->tximr, 0);
+       out_be32(&FIFO_512x(port)->rximr, 0);
+}
+
+static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->tximr,
+               (port->read_status_mask >> 16) & 0x7f);
+       out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
+}
+
+static unsigned long mpc512x_getuartclk(void *p)
+{
+       return mpc512x_find_ips_freq(p);
+}
+
+static struct psc_ops mpc512x_psc_ops = {
+       .fifo_init = mpc512x_psc_fifo_init,
+       .raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
+       .raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
+       .rx_rdy = mpc512x_psc_rx_rdy,
+       .tx_rdy = mpc512x_psc_tx_rdy,
+       .tx_empty = mpc512x_psc_tx_empty,
+       .stop_rx = mpc512x_psc_stop_rx,
+       .start_tx = mpc512x_psc_start_tx,
+       .stop_tx = mpc512x_psc_stop_tx,
+       .rx_clr_irq = mpc512x_psc_rx_clr_irq,
+       .tx_clr_irq = mpc512x_psc_tx_clr_irq,
+       .write_char = mpc512x_psc_write_char,
+       .read_char = mpc512x_psc_read_char,
+       .cw_disable_ints = mpc512x_psc_cw_disable_ints,
+       .cw_restore_ints = mpc512x_psc_cw_restore_ints,
+       .getuartclk = mpc512x_getuartclk,
 };
 #endif
 
+static struct psc_ops *psc_ops;
 
 /* ======================================================================== */
 /* UART operations                                                          */
@@ -145,8 +434,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
 static unsigned int
 mpc52xx_uart_tx_empty(struct uart_port *port)
 {
-       int status = in_be16(&PSC(port)->mpc52xx_psc_status);
-       return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
+       return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0;
 }
 
 static void
@@ -166,16 +454,14 @@ static void
 mpc52xx_uart_stop_tx(struct uart_port *port)
 {
        /* port->lock taken by caller */
-       port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+       psc_ops->stop_tx(port);
 }
 
 static void
 mpc52xx_uart_start_tx(struct uart_port *port)
 {
        /* port->lock taken by caller */
-       port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+       psc_ops->start_tx(port);
 }
 
 static void
@@ -188,8 +474,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
        if (ch) {
                /* Make sure tx interrupts are on */
                /* Truly necessary ??? They should be anyway */
-               port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
-               out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+               psc_ops->start_tx(port);
        }
 
        spin_unlock_irqrestore(&port->lock, flags);
@@ -199,8 +484,7 @@ static void
 mpc52xx_uart_stop_rx(struct uart_port *port)
 {
        /* port->lock taken by caller */
-       port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+       psc_ops->stop_rx(port);
 }
 
 static void
@@ -227,12 +511,12 @@ static int
 mpc52xx_uart_startup(struct uart_port *port)
 {
        struct mpc52xx_psc __iomem *psc = PSC(port);
-       struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port);
        int ret;
 
        /* Request IRQ */
        ret = request_irq(port->irq, mpc52xx_uart_int,
-               IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "mpc52xx_psc_uart", port);
+               IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+               "mpc52xx_psc_uart", port);
        if (ret)
                return ret;
 
@@ -242,15 +526,7 @@ mpc52xx_uart_startup(struct uart_port *port)
 
        out_be32(&psc->sicr, 0);        /* UART mode DCD ignored */
 
-       out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
-
-       out_8(&fifo->rfcntl, 0x00);
-       out_be16(&fifo->rfalarm, 0x1ff);
-       out_8(&fifo->tfcntl, 0x07);
-       out_be16(&fifo->tfalarm, 0x80);
-
-       port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
-       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+       psc_ops->fifo_init(port);
 
        out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
        out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
@@ -333,8 +609,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
         * boot for the console, all stuff is not yet ready to receive at that
         * time and that just makes the kernel oops */
        /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
-       while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
-              --j)
+       while (!mpc52xx_uart_tx_empty(port) && --j)
                udelay(1);
 
        if (!j)
@@ -462,11 +737,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
        unsigned short status;
 
        /* While we can read, do so ! */
-       while ((status = in_be16(&PSC(port)->mpc52xx_psc_status)) &
-               MPC52xx_PSC_SR_RXRDY) {
-
+       while (psc_ops->raw_rx_rdy(port)) {
                /* Get the char */
-               ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8);
+               ch = psc_ops->read_char(port);
 
                /* Handle sysreq char */
 #ifdef SUPPORT_SYSRQ
@@ -481,6 +754,8 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
                flag = TTY_NORMAL;
                port->icount.rx++;
 
+               status = in_be16(&PSC(port)->mpc52xx_psc_status);
+
                if (status & (MPC52xx_PSC_SR_PE |
                              MPC52xx_PSC_SR_FE |
                              MPC52xx_PSC_SR_RB)) {
@@ -510,7 +785,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
 
        tty_flip_buffer_push(tty);
 
-       return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;
+       return psc_ops->raw_rx_rdy(port);
 }
 
 static inline int
@@ -520,7 +795,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
 
        /* Process out of band chars */
        if (port->x_char) {
-               out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char);
+               psc_ops->write_char(port, port->x_char);
                port->icount.tx++;
                port->x_char = 0;
                return 1;
@@ -533,8 +808,8 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
        }
 
        /* Send chars */
-       while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) {
-               out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]);
+       while (psc_ops->raw_tx_rdy(port)) {
+               psc_ops->write_char(port, xmit->buf[xmit->tail]);
                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                port->icount.tx++;
                if (uart_circ_empty(xmit))
@@ -560,7 +835,6 @@ mpc52xx_uart_int(int irq, void *dev_id)
        struct uart_port *port = dev_id;
        unsigned long pass = ISR_PASS_LIMIT;
        unsigned int keepgoing;
-       unsigned short status;
 
        spin_lock(&port->lock);
 
@@ -569,18 +843,12 @@ mpc52xx_uart_int(int irq, void *dev_id)
                /* If we don't find anything to do, we stop */
                keepgoing = 0;
 
-               /* Read status */
-               status = in_be16(&PSC(port)->mpc52xx_psc_isr);
-               status &= port->read_status_mask;
-
-               /* Do we need to receive chars ? */
-               /* For this RX interrupts must be on and some chars waiting */
-               if (status & MPC52xx_PSC_IMR_RXRDY)
+               psc_ops->rx_clr_irq(port);
+               if (psc_ops->rx_rdy(port))
                        keepgoing |= mpc52xx_uart_int_rx_chars(port);
 
-               /* Do we need to send chars ? */
-               /* For this, TX must be ready and TX interrupt enabled */
-               if (status & MPC52xx_PSC_IMR_TXRDY)
+               psc_ops->tx_clr_irq(port);
+               if (psc_ops->tx_rdy(port))
                        keepgoing |= mpc52xx_uart_int_tx_chars(port);
 
                /* Limit number of iteration */
@@ -647,36 +915,33 @@ static void
 mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct uart_port *port = &mpc52xx_uart_ports[co->index];
-       struct mpc52xx_psc __iomem *psc = PSC(port);
        unsigned int i, j;
 
        /* Disable interrupts */
-       out_be16(&psc->mpc52xx_psc_imr, 0);
+       psc_ops->cw_disable_ints(port);
 
        /* Wait the TX buffer to be empty */
        j = 5000000;    /* Maximum wait */
-       while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
-              --j)
+       while (!mpc52xx_uart_tx_empty(port) && --j)
                udelay(1);
 
        /* Write all the chars */
        for (i = 0; i < count; i++, s++) {
                /* Line return handling */
                if (*s == '\n')
-                       out_8(&psc->mpc52xx_psc_buffer_8, '\r');
+                       psc_ops->write_char(port, '\r');
 
                /* Send the char */
-               out_8(&psc->mpc52xx_psc_buffer_8, *s);
+               psc_ops->write_char(port, *s);
 
                /* Wait the TX buffer to be empty */
                j = 20000;      /* Maximum wait */
-               while (!(in_be16(&psc->mpc52xx_psc_status) &
-                        MPC52xx_PSC_SR_TXEMP) && --j)
+               while (!mpc52xx_uart_tx_empty(port) && --j)
                        udelay(1);
        }
 
        /* Restore interrupt state */
-       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+       psc_ops->cw_restore_ints(port);
 }
 
 #if !defined(CONFIG_PPC_MERGE)
@@ -721,7 +986,7 @@ mpc52xx_console_setup(struct console *co, char *options)
 {
        struct uart_port *port = &mpc52xx_uart_ports[co->index];
        struct device_node *np = mpc52xx_uart_nodes[co->index];
-       unsigned int ipb_freq;
+       unsigned int uartclk;
        struct resource res;
        int ret;
 
@@ -753,17 +1018,16 @@ mpc52xx_console_setup(struct console *co, char *options)
                return ret;
        }
 
-       /* Search for bus-frequency property in this node or a parent */
-       ipb_freq = mpc52xx_find_ipb_freq(np);
-       if (ipb_freq == 0) {
-               pr_debug("Could not find IPB bus frequency!\n");
+       uartclk = psc_ops->getuartclk(np);
+       if (uartclk == 0) {
+               pr_debug("Could not find uart clock frequency!\n");
                return -EINVAL;
        }
 
        /* Basic port init. Needed since we use some uart_??? func before
         * real init for early access */
        spin_lock_init(&port->lock);
-       port->uartclk   = ipb_freq / 2;
+       port->uartclk = uartclk;
        port->ops       = &mpc52xx_uart_ops;
        port->mapbase = res.start;
        port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
@@ -945,11 +1209,25 @@ static struct platform_driver mpc52xx_uart_platform_driver = {
 /* OF Platform Driver                                                       */
 /* ======================================================================== */
 
+static struct of_device_id mpc52xx_uart_of_match[] = {
+#ifdef CONFIG_PPC_MPC52xx
+       { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
+       /* binding used by old lite5200 device trees: */
+       { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
+       /* binding used by efika: */
+       { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, },
+#endif
+#ifdef CONFIG_PPC_MPC512x
+       { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
+       {},
+#endif
+};
+
 static int __devinit
 mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
 {
        int idx = -1;
-       unsigned int ipb_freq;
+       unsigned int uartclk;
        struct uart_port *port = NULL;
        struct resource res;
        int ret;
@@ -965,10 +1243,9 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
        pr_debug("Found %s assigned to ttyPSC%x\n",
                 mpc52xx_uart_nodes[idx]->full_name, idx);
 
-       /* Search for bus-frequency property in this node or a parent */
-       ipb_freq = mpc52xx_find_ipb_freq(op->node);
-       if (ipb_freq == 0) {
-               dev_dbg(&op->dev, "Could not find IPB bus frequency!\n");
+       uartclk = psc_ops->getuartclk(op->node);
+       if (uartclk == 0) {
+               dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
                return -EINVAL;
        }
 
@@ -976,7 +1253,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
        port = &mpc52xx_uart_ports[idx];
 
        spin_lock_init(&port->lock);
-       port->uartclk   = ipb_freq / 2;
+       port->uartclk = uartclk;
        port->fifosize  = 512;
        port->iotype    = UPIO_MEM;
        port->flags     = UPF_BOOT_AUTOCONF |
@@ -1080,15 +1357,19 @@ mpc52xx_uart_of_enumerate(void)
        static int enum_done;
        struct device_node *np;
        const unsigned int *devno;
+       const struct  of_device_id *match;
        int i;
 
        if (enum_done)
                return;
 
        for_each_node_by_type(np, "serial") {
-               if (!of_match_node(mpc52xx_uart_of_match, np))
+               match = of_match_node(mpc52xx_uart_of_match, np);
+               if (!match)
                        continue;
 
+               psc_ops = match->data;
+
                /* Is a particular device number requested? */
                devno = of_get_property(np, "port-number", NULL);
                mpc52xx_uart_of_assign(np, devno ? *devno : -1);
@@ -1149,6 +1430,7 @@ mpc52xx_uart_init(void)
                return ret;
        }
 #else
+       psc_ops = &mpc52xx_psc_ops;
        ret = platform_driver_register(&mpc52xx_uart_platform_driver);
        if (ret) {
                printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
index bacf68dca01a04443a4f849d6dffb421a9883775..4e06ab6bcb6e80c15c5f71b723e912f9e7f53d08 100644 (file)
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #if defined(CONFIG_OF)
+#include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
+
+/* Match table for of_platform binding */
+static struct of_device_id ulite_of_match[] __devinitdata = {
+       { .compatible = "xlnx,opb-uartlite-1.00.b", },
+       { .compatible = "xlnx,xps-uartlite-1.00.a", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ulite_of_match);
+
 #endif
 
 #define ULITE_NAME             "ttyUL"
@@ -275,6 +286,9 @@ static void ulite_release_port(struct uart_port *port)
 
 static int ulite_request_port(struct uart_port *port)
 {
+       pr_debug("ulite console: port=%p; port->mapbase=%x\n",
+                port, port->mapbase);
+
        if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
                dev_err(port->dev, "Memory region busy\n");
                return -EBUSY;
@@ -375,32 +389,6 @@ static void ulite_console_write(struct console *co, const char *s,
                spin_unlock_irqrestore(&port->lock, flags);
 }
 
-#if defined(CONFIG_OF)
-static inline void __init ulite_console_of_find_device(int id)
-{
-       struct device_node *np;
-       struct resource res;
-       const unsigned int *of_id;
-       int rc;
-
-       for_each_compatible_node(np, NULL, "xilinx,uartlite") {
-               of_id = of_get_property(np, "port-number", NULL);
-               if ((!of_id) || (*of_id != id))
-                       continue;
-
-               rc = of_address_to_resource(np, 0, &res);
-               if (rc)
-                       continue;
-
-               ulite_ports[id].mapbase = res.start;
-               of_node_put(np);
-               return;
-       }
-}
-#else /* CONFIG_OF */
-static inline void __init ulite_console_of_find_device(int id) { /* do nothing */ }
-#endif /* CONFIG_OF */
-
 static int __init ulite_console_setup(struct console *co, char *options)
 {
        struct uart_port *port;
@@ -414,11 +402,7 @@ static int __init ulite_console_setup(struct console *co, char *options)
 
        port = &ulite_ports[co->index];
 
-       /* Check if it is an OF device */
-       if (!port->mapbase)
-               ulite_console_of_find_device(co->index);
-
-       /* Do we have a device now? */
+       /* Has the device been initialized yet? */
        if (!port->mapbase) {
                pr_debug("console on ttyUL%i not present\n", co->index);
                return -ENODEV;
@@ -617,13 +601,6 @@ static int __devexit ulite_of_remove(struct of_device *op)
        return ulite_release(&op->dev);
 }
 
-/* Match table for of_platform binding */
-static struct of_device_id __devinit ulite_of_match[] = {
-       { .type = "serial", .compatible = "xilinx,uartlite", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, ulite_of_match);
-
 static struct of_platform_driver ulite_of_driver = {
        .owner = THIS_MODULE,
        .name = "uartlite",
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
new file mode 100644 (file)
index 0000000..9b3f612
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Generic thermal sysfs drivers configuration
+#
+
+menuconfig THERMAL
+       bool "Generic Thermal sysfs driver"
+       default y
+       help
+         Generic Thermal Sysfs driver offers a generic mechanism for
+         thermal management. Usually it's made up of one or more thermal
+         zone and cooling device.
+         each thermal zone contains its own temperature, trip points,
+         cooling devices.
+         All platforms with ACPI thermal support can use this driver.
+         If you want this support, you should say Y here
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
new file mode 100644 (file)
index 0000000..8ef1232
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for sensor chip drivers.
+#
+
+obj-$(CONFIG_THERMAL)          += thermal.o
diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c
new file mode 100644 (file)
index 0000000..3273e34
--- /dev/null
@@ -0,0 +1,714 @@
+/*
+ *  thermal.c - Generic Thermal Management Sysfs support.
+ *
+ *  Copyright (C) 2008 Intel Corp
+ *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
+ *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+#include <linux/thermal.h>
+#include <linux/spinlock.h>
+
+MODULE_AUTHOR("Zhang Rui")
+MODULE_DESCRIPTION("Generic thermal management sysfs support");
+MODULE_LICENSE("GPL");
+
+#define PREFIX "Thermal: "
+
+struct thermal_cooling_device_instance {
+       int id;
+       char name[THERMAL_NAME_LENGTH];
+       struct thermal_zone_device *tz;
+       struct thermal_cooling_device *cdev;
+       int trip;
+       char attr_name[THERMAL_NAME_LENGTH];
+       struct device_attribute attr;
+       struct list_head node;
+};
+
+static DEFINE_IDR(thermal_tz_idr);
+static DEFINE_IDR(thermal_cdev_idr);
+static DEFINE_MUTEX(thermal_idr_lock);
+
+static LIST_HEAD(thermal_tz_list);
+static LIST_HEAD(thermal_cdev_list);
+static DEFINE_MUTEX(thermal_list_lock);
+
+static int get_idr(struct idr *idr, struct mutex *lock, int *id)
+{
+       int err;
+
+      again:
+       if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
+               return -ENOMEM;
+
+       if (lock)
+               mutex_lock(lock);
+       err = idr_get_new(idr, NULL, id);
+       if (lock)
+               mutex_unlock(lock);
+       if (unlikely(err == -EAGAIN))
+               goto again;
+       else if (unlikely(err))
+               return err;
+
+       *id = *id & MAX_ID_MASK;
+       return 0;
+}
+
+static void release_idr(struct idr *idr, struct mutex *lock, int id)
+{
+       if (lock)
+               mutex_lock(lock);
+       idr_remove(idr, id);
+       if (lock)
+               mutex_unlock(lock);
+}
+
+/* sys I/F for thermal zone */
+
+#define to_thermal_zone(_dev) \
+       container_of(_dev, struct thermal_zone_device, device)
+
+static ssize_t
+type_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+       return sprintf(buf, "%s\n", tz->type);
+}
+
+static ssize_t
+temp_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+       if (!tz->ops->get_temp)
+               return -EPERM;
+
+       return tz->ops->get_temp(tz, buf);
+}
+
+static ssize_t
+mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+       if (!tz->ops->get_mode)
+               return -EPERM;
+
+       return tz->ops->get_mode(tz, buf);
+}
+
+static ssize_t
+mode_store(struct device *dev, struct device_attribute *attr,
+          const char *buf, size_t count)
+{
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+       int result;
+
+       if (!tz->ops->set_mode)
+               return -EPERM;
+
+       result = tz->ops->set_mode(tz, buf);
+       if (result)
+               return result;
+
+       return count;
+}
+
+static ssize_t
+trip_point_type_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
+{
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+       int trip;
+
+       if (!tz->ops->get_trip_type)
+               return -EPERM;
+
+       if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
+               return -EINVAL;
+
+       return tz->ops->get_trip_type(tz, trip, buf);
+}
+
+static ssize_t
+trip_point_temp_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
+{
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+       int trip;
+
+       if (!tz->ops->get_trip_temp)
+               return -EPERM;
+
+       if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
+               return -EINVAL;
+
+       return tz->ops->get_trip_temp(tz, trip, buf);
+}
+
+static DEVICE_ATTR(type, 0444, type_show, NULL);
+static DEVICE_ATTR(temp, 0444, temp_show, NULL);
+static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
+
+static struct device_attribute trip_point_attrs[] = {
+       __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL),
+       __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL),
+       __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL),
+};
+
+#define TRIP_POINT_ATTR_ADD(_dev, _index, result)     \
+do {    \
+       result = device_create_file(_dev,       \
+                               &trip_point_attrs[_index * 2]); \
+       if (result)     \
+               break;  \
+       result = device_create_file(_dev,       \
+                       &trip_point_attrs[_index * 2 + 1]);     \
+} while (0)
+
+#define TRIP_POINT_ATTR_REMOVE(_dev, _index)   \
+do {   \
+       device_remove_file(_dev, &trip_point_attrs[_index * 2]);        \
+       device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]);    \
+} while (0)
+
+/* sys I/F for cooling device */
+#define to_cooling_device(_dev)        \
+       container_of(_dev, struct thermal_cooling_device, device)
+
+static ssize_t
+thermal_cooling_device_type_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct thermal_cooling_device *cdev = to_cooling_device(dev);
+
+       return sprintf(buf, "%s\n", cdev->type);
+}
+
+static ssize_t
+thermal_cooling_device_max_state_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct thermal_cooling_device *cdev = to_cooling_device(dev);
+
+       return cdev->ops->get_max_state(cdev, buf);
+}
+
+static ssize_t
+thermal_cooling_device_cur_state_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct thermal_cooling_device *cdev = to_cooling_device(dev);
+
+       return cdev->ops->get_cur_state(cdev, buf);
+}
+
+static ssize_t
+thermal_cooling_device_cur_state_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       struct thermal_cooling_device *cdev = to_cooling_device(dev);
+       int state;
+       int result;
+
+       if (!sscanf(buf, "%d\n", &state))
+               return -EINVAL;
+
+       if (state < 0)
+               return -EINVAL;
+
+       result = cdev->ops->set_cur_state(cdev, state);
+       if (result)
+               return result;
+       return count;
+}
+
+static struct device_attribute dev_attr_cdev_type =
+               __ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
+static DEVICE_ATTR(max_state, 0444,
+                  thermal_cooling_device_max_state_show, NULL);
+static DEVICE_ATTR(cur_state, 0644,
+                  thermal_cooling_device_cur_state_show,
+                  thermal_cooling_device_cur_state_store);
+
+static ssize_t
+thermal_cooling_device_trip_point_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct thermal_cooling_device_instance *instance;
+
+       instance =
+           container_of(attr, struct thermal_cooling_device_instance, attr);
+
+       if (instance->trip == THERMAL_TRIPS_NONE)
+               return sprintf(buf, "-1\n");
+       else
+               return sprintf(buf, "%d\n", instance->trip);
+}
+
+/* Device management */
+
+/**
+ * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
+ * this function is usually called in the thermal zone device .bind callback.
+ * @tz:                thermal zone device
+ * @trip:      indicates which trip point the cooling devices is
+ *             associated with in this thermal zone.
+ * @cdev:      thermal cooling device
+ */
+int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+                                    int trip,
+                                    struct thermal_cooling_device *cdev)
+{
+       struct thermal_cooling_device_instance *dev;
+       struct thermal_cooling_device_instance *pos;
+       int result;
+
+       if (trip >= tz->trips ||
+           (trip < 0 && trip != THERMAL_TRIPS_NONE))
+               return -EINVAL;
+
+       if (!tz || !cdev)
+               return -EINVAL;
+
+       dev =
+           kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       dev->tz = tz;
+       dev->cdev = cdev;
+       dev->trip = trip;
+       result = get_idr(&tz->idr, &tz->lock, &dev->id);
+       if (result)
+               goto free_mem;
+
+       sprintf(dev->name, "cdev%d", dev->id);
+       result =
+           sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
+       if (result)
+               goto release_idr;
+
+       sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
+       dev->attr.attr.name = dev->attr_name;
+       dev->attr.attr.mode = 0444;
+       dev->attr.show = thermal_cooling_device_trip_point_show;
+       result = device_create_file(&tz->device, &dev->attr);
+       if (result)
+               goto remove_symbol_link;
+
+       mutex_lock(&tz->lock);
+       list_for_each_entry(pos, &tz->cooling_devices, node)
+           if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
+               result = -EEXIST;
+               break;
+       }
+       if (!result)
+               list_add_tail(&dev->node, &tz->cooling_devices);
+       mutex_unlock(&tz->lock);
+
+       if (!result)
+               return 0;
+
+       device_remove_file(&tz->device, &dev->attr);
+      remove_symbol_link:
+       sysfs_remove_link(&tz->device.kobj, dev->name);
+      release_idr:
+       release_idr(&tz->idr, &tz->lock, dev->id);
+      free_mem:
+       kfree(dev);
+       return result;
+}
+EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
+
+/**
+ * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
+ * this function is usually called in the thermal zone device .unbind callback.
+ * @tz:                thermal zone device
+ * @trip:      indicates which trip point the cooling devices is
+ *             associated with in this thermal zone.
+ * @cdev:      thermal cooling device
+ */
+int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
+                                      int trip,
+                                      struct thermal_cooling_device *cdev)
+{
+       struct thermal_cooling_device_instance *pos, *next;
+
+       mutex_lock(&tz->lock);
+       list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) {
+               if (pos->tz == tz && pos->trip == trip
+                   && pos->cdev == cdev) {
+                       list_del(&pos->node);
+                       mutex_unlock(&tz->lock);
+                       goto unbind;
+               }
+       }
+       mutex_unlock(&tz->lock);
+
+       return -ENODEV;
+
+      unbind:
+       device_remove_file(&tz->device, &pos->attr);
+       sysfs_remove_link(&tz->device.kobj, pos->name);
+       release_idr(&tz->idr, &tz->lock, pos->id);
+       kfree(pos);
+       return 0;
+}
+EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
+
+static void thermal_release(struct device *dev)
+{
+       struct thermal_zone_device *tz;
+       struct thermal_cooling_device *cdev;
+
+       if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) {
+               tz = to_thermal_zone(dev);
+               kfree(tz);
+       } else {
+               cdev = to_cooling_device(dev);
+               kfree(cdev);
+       }
+}
+
+static struct class thermal_class = {
+       .name = "thermal",
+       .dev_release = thermal_release,
+};
+
+/**
+ * thermal_cooling_device_register - register a new thermal cooling device
+ * @type:      the thermal cooling device type.
+ * @devdata:   device private data.
+ * @ops:               standard thermal cooling devices callbacks.
+ */
+struct thermal_cooling_device *thermal_cooling_device_register(char *type,
+                      void *devdata, struct thermal_cooling_device_ops *ops)
+{
+       struct thermal_cooling_device *cdev;
+       struct thermal_zone_device *pos;
+       int result;
+
+       if (strlen(type) >= THERMAL_NAME_LENGTH)
+               return NULL;
+
+       if (!ops || !ops->get_max_state || !ops->get_cur_state ||
+               !ops->set_cur_state)
+               return NULL;
+
+       cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
+       if (!cdev)
+               return NULL;
+
+       result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
+       if (result) {
+               kfree(cdev);
+               return NULL;
+       }
+
+       strcpy(cdev->type, type);
+       cdev->ops = ops;
+       cdev->device.class = &thermal_class;
+       cdev->devdata = devdata;
+       sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id);
+       result = device_register(&cdev->device);
+       if (result) {
+               release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+               kfree(cdev);
+               return NULL;
+       }
+
+       /* sys I/F */
+       if (type) {
+               result = device_create_file(&cdev->device,
+                                           &dev_attr_cdev_type);
+               if (result)
+                       goto unregister;
+       }
+
+       result = device_create_file(&cdev->device, &dev_attr_max_state);
+       if (result)
+               goto unregister;
+
+       result = device_create_file(&cdev->device, &dev_attr_cur_state);
+       if (result)
+               goto unregister;
+
+       mutex_lock(&thermal_list_lock);
+       list_add(&cdev->node, &thermal_cdev_list);
+       list_for_each_entry(pos, &thermal_tz_list, node) {
+               if (!pos->ops->bind)
+                       continue;
+               result = pos->ops->bind(pos, cdev);
+               if (result)
+                       break;
+
+       }
+       mutex_unlock(&thermal_list_lock);
+
+       if (!result)
+               return cdev;
+
+      unregister:
+       release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+       device_unregister(&cdev->device);
+       return NULL;
+}
+EXPORT_SYMBOL(thermal_cooling_device_register);
+
+/**
+ * thermal_cooling_device_unregister - removes the registered thermal cooling device
+ *
+ * @cdev:      the thermal cooling device to remove.
+ *
+ * thermal_cooling_device_unregister() must be called when the device is no
+ * longer needed.
+ */
+void thermal_cooling_device_unregister(struct
+                                      thermal_cooling_device
+                                      *cdev)
+{
+       struct thermal_zone_device *tz;
+       struct thermal_cooling_device *pos = NULL;
+
+       if (!cdev)
+               return;
+
+       mutex_lock(&thermal_list_lock);
+       list_for_each_entry(pos, &thermal_cdev_list, node)
+           if (pos == cdev)
+               break;
+       if (pos != cdev) {
+               /* thermal cooling device not found */
+               mutex_unlock(&thermal_list_lock);
+               return;
+       }
+       list_del(&cdev->node);
+       list_for_each_entry(tz, &thermal_tz_list, node) {
+               if (!tz->ops->unbind)
+                       continue;
+               tz->ops->unbind(tz, cdev);
+       }
+       mutex_unlock(&thermal_list_lock);
+       if (cdev->type[0])
+               device_remove_file(&cdev->device,
+                                  &dev_attr_cdev_type);
+       device_remove_file(&cdev->device, &dev_attr_max_state);
+       device_remove_file(&cdev->device, &dev_attr_cur_state);
+
+       release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+       device_unregister(&cdev->device);
+       return;
+}
+EXPORT_SYMBOL(thermal_cooling_device_unregister);
+
+/**
+ * thermal_zone_device_register - register a new thermal zone device
+ * @type:      the thermal zone device type
+ * @trips:     the number of trip points the thermal zone support
+ * @devdata:   private device data
+ * @ops:       standard thermal zone device callbacks
+ *
+ * thermal_zone_device_unregister() must be called when the device is no
+ * longer needed.
+ */
+struct thermal_zone_device *thermal_zone_device_register(char *type,
+                                       int trips, void *devdata,
+                                       struct thermal_zone_device_ops *ops)
+{
+       struct thermal_zone_device *tz;
+       struct thermal_cooling_device *pos;
+       int result;
+       int count;
+
+       if (strlen(type) >= THERMAL_NAME_LENGTH)
+               return NULL;
+
+       if (trips > THERMAL_MAX_TRIPS || trips < 0)
+               return NULL;
+
+       if (!ops || !ops->get_temp)
+               return NULL;
+
+       tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
+       if (!tz)
+               return NULL;
+
+       INIT_LIST_HEAD(&tz->cooling_devices);
+       idr_init(&tz->idr);
+       mutex_init(&tz->lock);
+       result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
+       if (result) {
+               kfree(tz);
+               return NULL;
+       }
+
+       strcpy(tz->type, type);
+       tz->ops = ops;
+       tz->device.class = &thermal_class;
+       tz->devdata = devdata;
+       tz->trips = trips;
+       sprintf(tz->device.bus_id, "thermal_zone%d", tz->id);
+       result = device_register(&tz->device);
+       if (result) {
+               release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+               kfree(tz);
+               return NULL;
+       }
+
+       /* sys I/F */
+       if (type) {
+               result = device_create_file(&tz->device, &dev_attr_type);
+               if (result)
+                       goto unregister;
+       }
+
+       result = device_create_file(&tz->device, &dev_attr_temp);
+       if (result)
+               goto unregister;
+
+       if (ops->get_mode) {
+               result = device_create_file(&tz->device, &dev_attr_mode);
+               if (result)
+                       goto unregister;
+       }
+
+       for (count = 0; count < trips; count++) {
+               TRIP_POINT_ATTR_ADD(&tz->device, count, result);
+               if (result)
+                       goto unregister;
+       }
+
+       mutex_lock(&thermal_list_lock);
+       list_add_tail(&tz->node, &thermal_tz_list);
+       if (ops->bind)
+               list_for_each_entry(pos, &thermal_cdev_list, node) {
+                       result = ops->bind(tz, pos);
+                       if (result)
+                               break;
+               }
+       mutex_unlock(&thermal_list_lock);
+
+       if (!result)
+               return tz;
+
+      unregister:
+       release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+       device_unregister(&tz->device);
+       return NULL;
+}
+EXPORT_SYMBOL(thermal_zone_device_register);
+
+/**
+ * thermal_device_unregister - removes the registered thermal zone device
+ *
+ * @tz: the thermal zone device to remove
+ */
+void thermal_zone_device_unregister(struct thermal_zone_device *tz)
+{
+       struct thermal_cooling_device *cdev;
+       struct thermal_zone_device *pos = NULL;
+       int count;
+
+       if (!tz)
+               return;
+
+       mutex_lock(&thermal_list_lock);
+       list_for_each_entry(pos, &thermal_tz_list, node)
+           if (pos == tz)
+               break;
+       if (pos != tz) {
+               /* thermal zone device not found */
+               mutex_unlock(&thermal_list_lock);
+               return;
+       }
+       list_del(&tz->node);
+       if (tz->ops->unbind)
+               list_for_each_entry(cdev, &thermal_cdev_list, node)
+                   tz->ops->unbind(tz, cdev);
+       mutex_unlock(&thermal_list_lock);
+
+       if (tz->type[0])
+               device_remove_file(&tz->device, &dev_attr_type);
+       device_remove_file(&tz->device, &dev_attr_temp);
+       if (tz->ops->get_mode)
+               device_remove_file(&tz->device, &dev_attr_mode);
+
+       for (count = 0; count < tz->trips; count++)
+               TRIP_POINT_ATTR_REMOVE(&tz->device, count);
+
+       release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+       idr_destroy(&tz->idr);
+       mutex_destroy(&tz->lock);
+       device_unregister(&tz->device);
+       return;
+}
+EXPORT_SYMBOL(thermal_zone_device_unregister);
+
+static int __init thermal_init(void)
+{
+       int result = 0;
+
+       result = class_register(&thermal_class);
+       if (result) {
+               idr_destroy(&thermal_tz_idr);
+               idr_destroy(&thermal_cdev_idr);
+               mutex_destroy(&thermal_idr_lock);
+               mutex_destroy(&thermal_list_lock);
+       }
+       return result;
+}
+
+static void __exit thermal_exit(void)
+{
+       class_unregister(&thermal_class);
+       idr_destroy(&thermal_tz_idr);
+       idr_destroy(&thermal_cdev_idr);
+       mutex_destroy(&thermal_idr_lock);
+       mutex_destroy(&thermal_list_lock);
+}
+
+subsys_initcall(thermal_init);
+module_exit(thermal_exit);
index 924e2551044aee6b1f3e84b547c702ac30690412..dcd8073c236930ce7b2611760ef17daff36f8a53 100644 (file)
@@ -80,6 +80,15 @@ config BACKLIGHT_LOCOMO
          If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
          enable the LCD/backlight driver.
 
+config BACKLIGHT_OMAP1
+       tristate "OMAP1 PWL-based LCD Backlight"
+       depends on BACKLIGHT_CLASS_DEVICE && ARCH_OMAP1
+       default y
+       help
+         This driver controls the LCD backlight level and power for
+         the PWL module of OMAP1 processors.  Say Y if your board
+         uses this hardware.
+
 config BACKLIGHT_HP680
        tristate "HP Jornada 680 Backlight Driver"
        depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX
index 965a78b18118f09d70a3ef9dcdf429d40d725e90..33f6c7cecc73efb40edaad7a9df83d62a731e6b4 100644 (file)
@@ -7,5 +7,6 @@ obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_CORGI)  += corgi_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)  += hp680_bl.o
 obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_OMAP1)  += omap1_bl.o
 obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
 obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
index 4840fe217e4d30edc8dcc41318720a6e6fede59d..39394757679c0882f9a2765486163383bee0935c 100644 (file)
@@ -94,8 +94,10 @@ static ssize_t backlight_store_power(struct device *dev,
        mutex_lock(&bd->ops_lock);
        if (bd->ops) {
                pr_debug("backlight: set power to %d\n", power);
-               bd->props.power = power;
-               backlight_update_status(bd);
+               if (bd->props.power != power) {
+                       bd->props.power = power;
+                       backlight_update_status(bd);
+               }
                rc = count;
        }
        mutex_unlock(&bd->ops_lock);
@@ -132,8 +134,10 @@ static ssize_t backlight_store_brightness(struct device *dev,
                else {
                        pr_debug("backlight: set brightness to %d\n",
                                 brightness);
-                       bd->props.brightness = brightness;
-                       backlight_update_status(bd);
+                       if (bd->props.brightness != brightness) {
+                               bd->props.brightness = brightness;
+                               backlight_update_status(bd);
+                       }
                        rc = count;
                }
        }
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
new file mode 100644 (file)
index 0000000..891875d
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Backlight driver for OMAP based boards.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package 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 package 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 package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+
+#define OMAPBL_MAX_INTENSITY           0xff
+
+struct omap_backlight {
+       int powermode;
+       int current_intensity;
+
+       struct device *dev;
+       struct omap_backlight_config *pdata;
+};
+
+static void inline omapbl_send_intensity(int intensity)
+{
+       omap_writeb(intensity, OMAP_PWL_ENABLE);
+}
+
+static void inline omapbl_send_enable(int enable)
+{
+       omap_writeb(enable, OMAP_PWL_CLK_ENABLE);
+}
+
+static void omapbl_blank(struct omap_backlight *bl, int mode)
+{
+       if (bl->pdata->set_power)
+               bl->pdata->set_power(bl->dev, mode);
+
+       switch (mode) {
+       case FB_BLANK_NORMAL:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+               omapbl_send_intensity(0);
+               omapbl_send_enable(0);
+               break;
+
+       case FB_BLANK_UNBLANK:
+               omapbl_send_intensity(bl->current_intensity);
+               omapbl_send_enable(1);
+               break;
+       }
+}
+
+#ifdef CONFIG_PM
+static int omapbl_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct backlight_device *dev = platform_get_drvdata(pdev);
+       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+       omapbl_blank(bl, FB_BLANK_POWERDOWN);
+       return 0;
+}
+
+static int omapbl_resume(struct platform_device *pdev)
+{
+       struct backlight_device *dev = platform_get_drvdata(pdev);
+       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+       omapbl_blank(bl, bl->powermode);
+       return 0;
+}
+#else
+#define omapbl_suspend NULL
+#define omapbl_resume  NULL
+#endif
+
+static int omapbl_set_power(struct backlight_device *dev, int state)
+{
+       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+       omapbl_blank(bl, state);
+       bl->powermode = state;
+
+       return 0;
+}
+
+static int omapbl_update_status(struct backlight_device *dev)
+{
+       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+       if (bl->current_intensity != dev->props.brightness) {
+               if (bl->powermode == FB_BLANK_UNBLANK)
+                       omapbl_send_intensity(dev->props.brightness);
+               bl->current_intensity = dev->props.brightness;
+       }
+
+       if (dev->props.fb_blank != bl->powermode)
+               omapbl_set_power(dev, dev->props.fb_blank);
+
+       return 0;
+}
+
+static int omapbl_get_intensity(struct backlight_device *dev)
+{
+       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+       return bl->current_intensity;
+}
+
+static struct backlight_ops omapbl_ops = {
+       .get_brightness = omapbl_get_intensity,
+       .update_status  = omapbl_update_status,
+};
+
+static int omapbl_probe(struct platform_device *pdev)
+{
+       struct backlight_device *dev;
+       struct omap_backlight *bl;
+       struct omap_backlight_config *pdata = pdev->dev.platform_data;
+
+       if (!pdata)
+               return -ENXIO;
+
+       omapbl_ops.check_fb = pdata->check_fb;
+
+       bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL);
+       if (unlikely(!bl))
+               return -ENOMEM;
+
+       dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops);
+       if (IS_ERR(dev)) {
+               kfree(bl);
+               return PTR_ERR(dev);
+       }
+
+       bl->powermode = FB_BLANK_POWERDOWN;
+       bl->current_intensity = 0;
+
+       bl->pdata = pdata;
+       bl->dev = &pdev->dev;
+
+       platform_set_drvdata(pdev, dev);
+
+       omap_cfg_reg(PWL);      /* Conflicts with UART3 */
+
+       dev->props.fb_blank = FB_BLANK_UNBLANK;
+       dev->props.max_brightness = OMAPBL_MAX_INTENSITY;
+       dev->props.brightness = pdata->default_intensity;
+       omapbl_update_status(dev);
+
+       printk(KERN_INFO "OMAP LCD backlight initialised\n");
+
+       return 0;
+}
+
+static int omapbl_remove(struct platform_device *pdev)
+{
+       struct backlight_device *dev = platform_get_drvdata(pdev);
+       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+
+       backlight_device_unregister(dev);
+       kfree(bl);
+
+       return 0;
+}
+
+static struct platform_driver omapbl_driver = {
+       .probe          = omapbl_probe,
+       .remove         = omapbl_remove,
+       .suspend        = omapbl_suspend,
+       .resume         = omapbl_resume,
+       .driver         = {
+               .name   = "omap-bl",
+       },
+};
+
+static int __init omapbl_init(void)
+{
+       return platform_driver_register(&omapbl_driver);
+}
+
+static void __exit omapbl_exit(void)
+{
+       platform_driver_unregister(&omapbl_driver);
+}
+
+module_init(omapbl_init);
+module_exit(omapbl_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski <balrog@zabor.org>");
+MODULE_DESCRIPTION("OMAP LCD Backlight driver");
+MODULE_LICENSE("GPL");
index e38d3b7c3ad7b28e5b63909a83885ff535d17f17..7b3a8423f485e340afffb81d6f0dbc4c933eec83 100644 (file)
@@ -459,8 +459,8 @@ static int __devexit xilinxfb_of_remove(struct of_device *op)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id __devinit xilinxfb_of_match[] = {
-       { .compatible = "xilinx,ml300-fb", },
+static struct of_device_id xilinxfb_of_match[] __devinitdata = {
+       { .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
        {},
 };
 MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
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);
index 5c5137c11484d22f22c18412a3d26ad231e898cc..6a28842052eac1ccf3c600817b3722c344036e7d 100644 (file)
@@ -573,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 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 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 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 bb9948cdd50f8499d5cfc689f00288dad6fd2495..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 *);
index 03978ec2a91c5c547138e9313d276f08cad6e02d..c620068054277672aecefb90115c31daf26c4957 100644 (file)
@@ -1181,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);
@@ -1220,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);
@@ -1286,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 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 1ba18b72d43ae06234e6fe2a2f5aebcdc006af97..22f1010bf79f9f40cb9557d100694f2af9397f74 100644 (file)
@@ -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);
@@ -746,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;
@@ -1041,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");
@@ -1080,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 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 8a9ce2d09bde9e7bd418b4cf1294185645d77f49..eb95670a27ebafac6a9a4c593ef37e98a0f29ebf 100644 (file)
@@ -2654,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);
@@ -2699,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
@@ -2742,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) {
@@ -2783,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 92b83b004dd8b09c5b8a981750af3521bc424b81..dec3e0d88ab1536745ccf52c70a23a2a6a04ca57 100644 (file)
@@ -1037,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);
 }
@@ -1076,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 343677e8c3500164b09d12513772d00f7d2d7a91..cf2a2c3660ec793b4e20d090bd16e6192d824644 100644 (file)
@@ -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,
@@ -1378,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;
                }
@@ -1508,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;
 
@@ -1877,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);
        /*
@@ -1941,7 +1945,7 @@ out_fail:
        sb->s_fs_info = NULL;
        kfree(sbi);
        lock_kernel();
-       return -EINVAL;
+       return ret;
 }
 
 /*
@@ -1977,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;
        }
@@ -1991,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 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 0e9055cf700e606f1aacb5432b8744a810242e11..f4e3874522465cb52324fa7d317dbc2a11e83fb4 100644 (file)
@@ -2680,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);
@@ -2720,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
@@ -2758,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) {
@@ -2811,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 c89bb8797765b9edd1a8a74a8404216d35b8e969..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,
@@ -1805,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;
@@ -2237,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);
 
@@ -2330,7 +2334,7 @@ out_fail:
        sb->s_fs_info = NULL;
        kfree(sbi);
        lock_kernel();
-       return -EINVAL;
+       return ret;
 }
 
 /*
@@ -2366,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;
        }
@@ -2380,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 24c0aaa5ae80d6de0cb876f554da57f2cca864b7..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);
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 f56f91bd38bea8b978bb26c38d8e3e3bb993e00a..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);
@@ -1006,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 c90f633d0b578766103a52d8d277e1500d168f6d..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)
 {
@@ -515,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 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 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 77fc5838609ce3d3a3246abdeb8910ab593f782a..4c80404a9abae4b61e075135bb62441450596b11 100644 (file)
@@ -176,7 +176,7 @@ static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct
        spin_unlock(&inode->i_lock);
 }
 
-struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
+static struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
 {
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
        struct posix_acl *acl;
@@ -345,8 +345,10 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode)
                if (!clone)
                        return -ENOMEM;
                rc = posix_acl_create_masq(clone, (mode_t *)i_mode);
-               if (rc < 0)
+               if (rc < 0) {
+                       posix_acl_release(clone);
                        return rc;
+               }
                if (rc > 0)
                        jffs2_iset_acl(inode, &f->i_acl_access, clone);
 
index 76c6ebd1acd975840d303ddc65b0ecde54091579..0bb7f003fd80bb8b64909fedf420c3af327198c9 100644 (file)
@@ -28,7 +28,6 @@ struct jffs2_acl_header {
 
 #define JFFS2_ACL_NOT_CACHED ((void *)-1)
 
-extern struct posix_acl *jffs2_get_acl(struct inode *inode, int type);
 extern int jffs2_permission(struct inode *, int, struct nameidata *);
 extern int jffs2_acl_chmod(struct inode *);
 extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *);
@@ -40,7 +39,6 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler;
 
 #else
 
-#define jffs2_get_acl(inode, type)             (NULL)
 #define jffs2_permission                       (NULL)
 #define jffs2_acl_chmod(inode)                 (0)
 #define jffs2_init_acl_pre(dir_i,inode,mode)   (0)
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..e26ea78c7892f7a4f157819a06e052add03057fd 100644 (file)
@@ -97,11 +97,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid);
 
        if (ivalid & ATTR_MODE)
-               if (iattr->ia_mode & S_ISGID &&
-                   !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
-                       ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
-               else
-                       ri->mode = cpu_to_jemode(iattr->ia_mode);
+               ri->mode = cpu_to_jemode(iattr->ia_mode);
        else
                ri->mode = cpu_to_jemode(inode->i_mode);
 
@@ -230,16 +226,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 +253,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 +306,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 +333,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 +530,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 +555,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 +625,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 4bf86088b3ae397c18125fcc74e78eabaa02bea7..87c6f555e1a0a696ee2fe52e57c9b3978bc8716f 100644 (file)
@@ -32,15 +32,18 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new
                if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) {
                        /* Duplicate. Free one */
                        if (new->version < (*prev)->version) {
-                               dbg_dentlist("Eep! Marking new dirent node is obsolete, old is \"%s\", ino #%u\n",
+                               dbg_dentlist("Eep! Marking new dirent node obsolete, old is \"%s\", ino #%u\n",
                                        (*prev)->name, (*prev)->ino);
                                jffs2_mark_node_obsolete(c, new->raw);
                                jffs2_free_full_dirent(new);
                        } else {
-                               dbg_dentlist("marking old dirent \"%s\", ino #%u bsolete\n",
+                               dbg_dentlist("marking old dirent \"%s\", ino #%u obsolete\n",
                                        (*prev)->name, (*prev)->ino);
                                new->next = (*prev)->next;
-                               jffs2_mark_node_obsolete(c, ((*prev)->raw));
+                               /* It may have been a 'placeholder' deletion dirent, 
+                                  if jffs2_can_mark_obsolete() (see jffs2_do_unlink()) */
+                               if ((*prev)->raw)
+                                       jffs2_mark_node_obsolete(c, ((*prev)->raw));
                                jffs2_free_full_dirent(*prev);
                                *prev = new;
                        }
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 6c1ba3566f58b4c498c1cfa7a3a627db9e089eeb..e512a93d624954e04b70ab0a27bf85eb43a61fea 100644 (file)
@@ -37,23 +37,24 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
 
        BUG_ON(tn->csize == 0);
 
-       if (!jffs2_is_writebuffered(c))
-               goto adj_acc;
-
        /* Calculate how many bytes were already checked */
        ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode);
-       len = ofs % c->wbuf_pagesize;
-       if (likely(len))
-               len = c->wbuf_pagesize - len;
-
-       if (len >= tn->csize) {
-               dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n",
-                       ref_offset(ref), tn->csize, ofs);
-               goto adj_acc;
-       }
+       len = tn->csize;
+
+       if (jffs2_is_writebuffered(c)) {
+               int adj = ofs % c->wbuf_pagesize;
+               if (likely(adj))
+                       adj = c->wbuf_pagesize - adj;
+
+               if (adj >= tn->csize) {
+                       dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n",
+                                     ref_offset(ref), tn->csize, ofs);
+                       goto adj_acc;
+               }
 
-       ofs += len;
-       len = tn->csize - len;
+               ofs += adj;
+               len -= adj;
+       }
 
        dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n",
                ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len);
@@ -63,7 +64,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
         * adding and jffs2_flash_read_end() interface. */
        if (c->mtd->point) {
                err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
-               if (!err && retlen < tn->csize) {
+               if (!err && retlen < len) {
                        JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
                        c->mtd->unpoint(c->mtd, buffer, ofs, retlen);
                } else if (err)
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..776f13cbf2b5e62fef50abfee752e71f93b5e0ee 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) {
@@ -582,7 +582,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                jffs2_add_fd_to_list(c, fd, &dir_f->dents);
                up(&dir_f->sem);
        } else {
-               struct jffs2_full_dirent **prev = &dir_f->dents;
+               struct jffs2_full_dirent *fd = dir_f->dents;
                uint32_t nhash = full_name_hash(name, namelen);
 
                /* We don't actually want to reserve any space, but we do
@@ -590,21 +590,22 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                down(&c->alloc_sem);
                down(&dir_f->sem);
 
-               while ((*prev) && (*prev)->nhash <= nhash) {
-                       if ((*prev)->nhash == nhash &&
-                           !memcmp((*prev)->name, name, namelen) &&
-                           !(*prev)->name[namelen]) {
-                               struct jffs2_full_dirent *this = *prev;
+               for (fd = dir_f->dents; fd; fd = fd->next) {
+                       if (fd->nhash == nhash &&
+                           !memcmp(fd->name, name, namelen) &&
+                           !fd->name[namelen]) {
 
                                D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n",
-                                         this->ino, ref_offset(this->raw)));
-
-                               *prev = this->next;
-                               jffs2_mark_node_obsolete(c, (this->raw));
-                               jffs2_free_full_dirent(this);
+                                         fd->ino, ref_offset(fd->raw)));
+                               jffs2_mark_node_obsolete(c, fd->raw);
+                               /* We don't want to remove it from the list immediately,
+                                  because that screws up getdents()/seek() semantics even
+                                  more than they're screwed already. Turn it into a
+                                  node-less deletion dirent instead -- a placeholder */
+                               fd->raw = NULL;
+                               fd->ino = 0;
                                break;
                        }
-                       prev = &((*prev)->next);
                }
                up(&dir_f->sem);
        }
@@ -630,7 +631,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                                        D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
                                                fd->name, dead_f->inocache->ino));
                                }
-                               jffs2_mark_node_obsolete(c, fd->raw);
+                               if (fd->raw)
+                                       jffs2_mark_node_obsolete(c, fd->raw);
                                jffs2_free_full_dirent(fd);
                        }
                }
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 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 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 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 a5bd23ce0e46fde64420455c7097338954da0f76..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 */
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 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 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 347a911d8237828d4e49b154a2d594081d789f4b..47a1fd8f2d8a2c61629efe6999fcda26613a94f0 100644 (file)
@@ -117,10 +117,6 @@ extern u32 acpi_dbg_layer;
 
 extern u32 acpi_gbl_nesting_level;
 
-/* Event counters */
-
-ACPI_EXTERN u32 acpi_gpe_count;
-
 /* Support for dynamic control method tracing mechanism */
 
 ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
index 45662f6dbdb66b34b8966670187ffd6655737aa6..99d171c87c84897123d7cdde56a8c7d83300c5f5 100644 (file)
 #define ACPI_FUNCTION_NAME(name)
 #endif
 
-#ifdef DEBUG_FUNC_TRACE
+#ifdef CONFIG_ACPI_DEBUG_FUNC_TRACE
 
 #define ACPI_FUNCTION_TRACE(a)          ACPI_FUNCTION_NAME(a) \
                          acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
 
 #endif                         /* ACPI_SIMPLE_RETURN_MACROS */
 
-#else /* !DEBUG_FUNC_TRACE */
+#else /* !CONFIG_ACPI_DEBUG_FUNC_TRACE */
 
 #define ACPI_FUNCTION_TRACE(a)
 #define ACPI_FUNCTION_TRACE_PTR(a,b)
 #define return_UINT32(s)                return(s)
 #define return_PTR(s)                   return(s)
 
-#endif /* DEBUG_FUNC_TRACE */
+#endif /* CONFIG_ACPI_DEBUG_FUNC_TRACE */
 
 /* Conditional execution */
 
index fb7171b1bd22e900349126212f8fceb4f997d8e8..2f1c68c7a7270ea7098a39509690eb5d03614c1d 100644 (file)
@@ -321,6 +321,11 @@ struct acpi_bus_event {
 
 extern struct kobject *acpi_kobj;
 extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
+void acpi_bus_private_data_handler(acpi_handle, u32, void *);
+int acpi_bus_get_private_data(acpi_handle, void **);
+extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
+extern int register_acpi_notifier(struct notifier_block *);
+extern int unregister_acpi_notifier(struct notifier_block *);
 /*
  * External Functions
  */
index f85f77a538aa67afb418b4b35ba8c3ccd945516f..9757a040a5057e82678490bd35713488a6eab893 100644 (file)
@@ -48,6 +48,7 @@
 #define ACPI_BUTTON_HID_SLEEPF         "LNXSLPBN"
 #define ACPI_VIDEO_HID                 "LNXVIDEO"
 #define ACPI_BAY_HID                   "LNXIOBAY"
+#define ACPI_DOCK_HID                  "LNXDOCK"
 
 /* --------------------------------------------------------------------------
                                        PCI
@@ -73,7 +74,6 @@ struct pci_bus;
 
 acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id);
 int acpi_pci_bind(struct acpi_device *device);
-int acpi_pci_unbind(struct acpi_device *device);
 int acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id,
                       struct pci_bus *bus);
 
index 62c5ee4311da36deec078b467ca381c36919e9ed..173972672175588c181718aef6cf7f1537c37758 100644 (file)
@@ -15,7 +15,6 @@ extern int pxm_to_node(int);
 extern int node_to_pxm(int);
 extern void __acpi_map_pxm_to_node(int, int);
 extern int acpi_map_pxm_to_node(int);
-extern void __cpuinit acpi_unmap_pxm_to_node(int);
 
 #endif                         /* CONFIG_ACPI_NUMA */
 #endif                         /* __ACP_NUMA_H */
index ca882b8e7d108e9d069ae053dd384e459bcec9a4..022a5fd80c8e60deee43bddd7aacda0bd45a4420 100644 (file)
@@ -181,6 +181,9 @@ acpi_os_install_interrupt_handler(u32 gsi,
 acpi_status
 acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler service_routine);
 
+void acpi_os_gpe_count(u32 gpe_number);
+void acpi_os_fixed_event_count(u32 fixed_event_number);
+
 /*
  * Threads and Scheduling
  */
@@ -239,8 +242,8 @@ acpi_status acpi_os_validate_interface(char *interface);
 acpi_status acpi_osi_invalidate(char* interface);
 
 acpi_status
-acpi_os_validate_address(u8 space_id,
-                        acpi_physical_address address, acpi_size length);
+acpi_os_validate_address(u8 space_id, acpi_physical_address address,
+                        acpi_size length, char *name);
 
 u64 acpi_os_get_timer(void);
 
index 6e253b5b0f3bc33ba5d7c622bb0d689ee4df2c12..cdc8004cfd12c73e7f0ffdc9ef2394779eefa536 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/kernel.h>
 #include <linux/cpu.h>
 #include <linux/cpuidle.h>
-
+#include <linux/thermal.h>
 #include <asm/acpi.h>
 
 #define ACPI_PROCESSOR_BUSY_METRIC     10
@@ -34,6 +34,7 @@
 
 #define ACPI_CSTATE_SYSTEMIO   (0)
 #define ACPI_CSTATE_FFH                (1)
+#define ACPI_CSTATE_HALT       (2)
 
 /* Power Management */
 
@@ -64,7 +65,7 @@ struct acpi_processor_cx {
        u8 valid;
        u8 type;
        u32 address;
-       u8 space_id;
+       u8 entry_method;
        u8 index;
        u32 latency;
        u32 latency_ticks;
@@ -176,6 +177,8 @@ struct acpi_processor_throttling {
        u32 address;
        u8 duty_offset;
        u8 duty_width;
+       u8 tsd_valid_flag;
+       unsigned int shared_type;
        struct acpi_processor_tx states[ACPI_PROCESSOR_MAX_THROTTLING];
 };
 
@@ -218,7 +221,7 @@ struct acpi_processor {
        struct acpi_processor_performance *performance;
        struct acpi_processor_throttling throttling;
        struct acpi_processor_limit limit;
-
+       struct thermal_cooling_device *cdev;
        /* the _PDC objects for this processor, if any */
        struct acpi_object_list *pdc;
 };
@@ -316,7 +319,7 @@ static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
 int acpi_processor_get_throttling_info(struct acpi_processor *pr);
 extern int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
 extern struct file_operations acpi_processor_throttling_fops;
-
+extern void acpi_processor_throttling_init(void);
 /* in processor_idle.c */
 int acpi_processor_power_init(struct acpi_processor *pr,
                              struct acpi_device *device);
@@ -330,7 +333,7 @@ extern struct cpuidle_driver acpi_idle_driver;
 /* in processor_thermal.c */
 int acpi_processor_get_limit_info(struct acpi_processor *pr);
 extern struct file_operations acpi_processor_limit_fops;
-
+extern struct thermal_cooling_device_ops processor_cooling_ops;
 #ifdef CONFIG_CPU_FREQ
 void acpi_thermal_cpufreq_init(void);
 void acpi_thermal_cpufreq_exit(void);
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 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 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 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 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 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 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 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 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 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 d029b75bcf04b31af41bc79074b76736db4ccad2..13135d4821d8f1a3bfd4f6aecc9070b008db4c7d 100644 (file)
@@ -191,7 +191,8 @@ static inline pte_t pte_mkcache(pte_t pte)
 #define pgd_index(address)     ((address) >> PGDIR_SHIFT)
 
 /* to find an entry in a page-table-directory */
-static inline pgd_t *pgd_offset(struct mm_struct *mm, unsigned long address)
+static inline pgd_t *pgd_offset(const struct mm_struct *mm,
+                               unsigned long address)
 {
        return mm->pgd + pgd_index(address);
 }
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 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 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 528ef183c221d522f41f92e47cf572dda50e0c91..1e79673b7316f58003cec08bfee11ed45ad96f2a 100644 (file)
@@ -46,7 +46,7 @@ enum powerpc_oprofile_type {
        PPC_OPROFILE_RS64 = 1,
        PPC_OPROFILE_POWER4 = 2,
        PPC_OPROFILE_G4 = 3,
-       PPC_OPROFILE_BOOKE = 4,
+       PPC_OPROFILE_FSL_EMB = 4,
        PPC_OPROFILE_CELL = 5,
        PPC_OPROFILE_PA6T = 6,
 };
index af5fb31af559d6dbf5a0ecb95f1705d952419fa5..be6c879e8760b11ba3b92de41e39f72622b6fb4f 100644 (file)
@@ -59,25 +59,36 @@ do {                                                                \
 /* R/W of indirect DCRs make use of standard naming conventions for DCRs */
 extern spinlock_t dcr_ind_lock;
 
-#define mfdcri(base, reg)                              \
-({                                                     \
-       unsigned long flags;                            \
-       unsigned int val;                               \
-       spin_lock_irqsave(&dcr_ind_lock, flags);        \
-       mtdcr(DCRN_ ## base ## _CONFIG_ADDR, reg);      \
-       val = mfdcr(DCRN_ ## base ## _CONFIG_DATA);     \
-       spin_unlock_irqrestore(&dcr_ind_lock, flags);   \
-       val;                                            \
-})
+static inline unsigned __mfdcri(int base_addr, int base_data, int reg)
+{
+       unsigned long flags;
+       unsigned int val;
 
-#define mtdcri(base, reg, data)                                \
-do {                                                   \
-       unsigned long flags;                            \
-       spin_lock_irqsave(&dcr_ind_lock, flags);        \
-       mtdcr(DCRN_ ## base ## _CONFIG_ADDR, reg);      \
-       mtdcr(DCRN_ ## base ## _CONFIG_DATA, data);     \
-       spin_unlock_irqrestore(&dcr_ind_lock, flags);   \
-} while (0)
+       spin_lock_irqsave(&dcr_ind_lock, flags);
+       __mtdcr(base_addr, reg);
+       val = __mfdcr(base_data);
+       spin_unlock_irqrestore(&dcr_ind_lock, flags);
+       return val;
+}
+
+static inline void __mtdcri(int base_addr, int base_data, int reg,
+                           unsigned val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dcr_ind_lock, flags);
+       __mtdcr(base_addr, reg);
+       __mtdcr(base_data, val);
+       spin_unlock_irqrestore(&dcr_ind_lock, flags);
+}
+
+#define mfdcri(base, reg)      __mfdcri(DCRN_ ## base ## _CONFIG_ADDR, \
+                                        DCRN_ ## base ## _CONFIG_DATA, \
+                                        reg)
+
+#define mtdcri(base, reg, data)        __mtdcri(DCRN_ ## base ## _CONFIG_ADDR, \
+                                        DCRN_ ## base ## _CONFIG_DATA, \
+                                        reg, data)
 
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
index 6bd07ef78ac42b27aac921d650a2b04f6856c45b..9080d85cb9d006619d0b8543f36232c41b594bf1 100644 (file)
@@ -165,8 +165,10 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32];
  * This is used to ensure we don't load something for the wrong architecture.
  */
 #define elf_check_arch(x) ((x)->e_machine == ELF_ARCH)
+#define compat_elf_check_arch(x)       ((x)->e_machine == EM_PPC)
 
 #define USE_ELF_CORE_DUMP
+#define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
diff --git a/include/asm-powerpc/mpc512x.h b/include/asm-powerpc/mpc512x.h
new file mode 100644 (file)
index 0000000..c48a165
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: John Rigby, <jrigby@freescale.com>, Friday Apr 13 2007
+ *
+ * Description:
+ * MPC5121 Prototypes and definitions
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_POWERPC_MPC512x_H__
+#define __ASM_POWERPC_MPC512x_H__
+
+extern unsigned long mpc512x_find_ips_freq(struct device_node *node);
+
+#endif /* __ASM_POWERPC_MPC512x_H__ */
+
index bea42b95390f3aec6e1bf6732faba42f9785ddd4..710c5d36efaa08496f1a473633acfdf132b3eba1 100644 (file)
@@ -190,5 +190,53 @@ struct mpc52xx_psc_fifo {
        u16             tflwfptr;       /* PSC + 0x9e */
 };
 
+#define MPC512x_PSC_FIFO_RESET_SLICE   0x80
+#define MPC512x_PSC_FIFO_ENABLE_SLICE  0x01
+#define MPC512x_PSC_FIFO_ENABLE_DMA    0x04
+
+#define MPC512x_PSC_FIFO_EMPTY         0x1
+#define MPC512x_PSC_FIFO_FULL          0x2
+#define MPC512x_PSC_FIFO_ALARM         0x4
+#define MPC512x_PSC_FIFO_URERR         0x8
+#define MPC512x_PSC_FIFO_ORERR         0x01
+#define MPC512x_PSC_FIFO_MEMERROR      0x02
+
+struct mpc512x_psc_fifo {
+       u32             reserved1[10];
+       u32             txcmd;          /* PSC + 0x80 */
+       u32             txalarm;        /* PSC + 0x84 */
+       u32             txsr;           /* PSC + 0x88 */
+       u32             txisr;          /* PSC + 0x8c */
+       u32             tximr;          /* PSC + 0x90 */
+       u32             txcnt;          /* PSC + 0x94 */
+       u32             txptr;          /* PSC + 0x98 */
+       u32             txsz;           /* PSC + 0x9c */
+       u32             reserved2[7];
+       union {
+               u8      txdata_8;
+               u16     txdata_16;
+               u32     txdata_32;
+       } txdata;                       /* PSC + 0xbc */
+#define txdata_8 txdata.txdata_8
+#define txdata_16 txdata.txdata_16
+#define txdata_32 txdata.txdata_32
+       u32             rxcmd;          /* PSC + 0xc0 */
+       u32             rxalarm;        /* PSC + 0xc4 */
+       u32             rxsr;           /* PSC + 0xc8 */
+       u32             rxisr;          /* PSC + 0xcc */
+       u32             rximr;          /* PSC + 0xd0 */
+       u32             rxcnt;          /* PSC + 0xd4 */
+       u32             rxptr;          /* PSC + 0xd8 */
+       u32             rxsz;           /* PSC + 0xdc */
+       u32             reserved3[7];
+       union {
+               u8      rxdata_8;
+               u16     rxdata_16;
+               u32     rxdata_32;
+       } rxdata;                       /* PSC + 0xfc */
+#define rxdata_8 rxdata.rxdata_8
+#define rxdata_16 rxdata.rxdata_16
+#define rxdata_32 rxdata.rxdata_32
+};
 
 #endif  /* __ASM_MPC52xx_PSC_H__ */
index 938fefb4c4bca07d6873829d6fceda73f9742496..95035c602ba625b505738d81e0b957a417ce048a 100644 (file)
@@ -54,7 +54,7 @@ struct op_powerpc_model {
        int num_counters;
 };
 
-extern struct op_powerpc_model op_model_fsl_booke;
+extern struct op_powerpc_model op_model_fsl_emb;
 extern struct op_powerpc_model op_model_rs64;
 extern struct op_powerpc_model op_model_power4;
 extern struct op_powerpc_model op_model_7450;
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 ffc150f602b81d5a6c55ea9f4b97d00ef5a0550e..891d68932f39975143b7dcc42fe4e0fbf96a414a 100644 (file)
@@ -55,6 +55,8 @@ struct pt_regs {
 
 #ifdef __powerpc64__
 
+#define __ARCH_WANT_COMPAT_SYS_PTRACE
+
 #define STACK_FRAME_OVERHEAD   112     /* size of minimum stack frame */
 
 /* Size of dummy stack frame allocated when calling signal handler. */
index 2408a29507e599fd457a45369fe688e4499e1147..0d6238987df864f9b7f2d4f1cff8a6b7fade4fda 100644 (file)
 #include <asm/reg_booke.h>
 #endif /* CONFIG_BOOKE || CONFIG_40x */
 
+#ifdef CONFIG_FSL_EMB_PERFMON
+#include <asm/reg_fsl_emb.h>
+#endif
+
 #ifdef CONFIG_8xx
 #include <asm/reg_8xx.h>
 #endif /* CONFIG_8xx */
index 0405ef479814f10455236b08956d833d21c6da77..cf54a3f31753895d44e32b18decd248c4380deb2 100644 (file)
@@ -9,68 +9,6 @@
 #ifndef __ASM_POWERPC_REG_BOOKE_H__
 #define __ASM_POWERPC_REG_BOOKE_H__
 
-#ifndef __ASSEMBLY__
-/* Performance Monitor Registers */
-#define mfpmr(rn)      ({unsigned int rval; \
-                       asm volatile("mfpmr %0," __stringify(rn) \
-                                    : "=r" (rval)); rval;})
-#define mtpmr(rn, v)   asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
-#endif /* __ASSEMBLY__ */
-
-/* Freescale Book E Performance Monitor APU Registers */
-#define PMRN_PMC0      0x010   /* Performance Monitor Counter 0 */
-#define PMRN_PMC1      0x011   /* Performance Monitor Counter 1 */
-#define PMRN_PMC2      0x012   /* Performance Monitor Counter 1 */
-#define PMRN_PMC3      0x013   /* Performance Monitor Counter 1 */
-#define PMRN_PMLCA0    0x090   /* PM Local Control A0 */
-#define PMRN_PMLCA1    0x091   /* PM Local Control A1 */
-#define PMRN_PMLCA2    0x092   /* PM Local Control A2 */
-#define PMRN_PMLCA3    0x093   /* PM Local Control A3 */
-
-#define PMLCA_FC       0x80000000      /* Freeze Counter */
-#define PMLCA_FCS      0x40000000      /* Freeze in Supervisor */
-#define PMLCA_FCU      0x20000000      /* Freeze in User */
-#define PMLCA_FCM1     0x10000000      /* Freeze when PMM==1 */
-#define PMLCA_FCM0     0x08000000      /* Freeze when PMM==0 */
-#define PMLCA_CE       0x04000000      /* Condition Enable */
-
-#define PMLCA_EVENT_MASK 0x007f0000    /* Event field */
-#define PMLCA_EVENT_SHIFT      16
-
-#define PMRN_PMLCB0    0x110   /* PM Local Control B0 */
-#define PMRN_PMLCB1    0x111   /* PM Local Control B1 */
-#define PMRN_PMLCB2    0x112   /* PM Local Control B2 */
-#define PMRN_PMLCB3    0x113   /* PM Local Control B3 */
-
-#define PMLCB_THRESHMUL_MASK   0x0700  /* Threshhold Multiple Field */
-#define PMLCB_THRESHMUL_SHIFT  8
-
-#define PMLCB_THRESHOLD_MASK   0x003f  /* Threshold Field */
-#define PMLCB_THRESHOLD_SHIFT  0
-
-#define PMRN_PMGC0     0x190   /* PM Global Control 0 */
-
-#define PMGC0_FAC      0x80000000      /* Freeze all Counters */
-#define PMGC0_PMIE     0x40000000      /* Interrupt Enable */
-#define PMGC0_FCECE    0x20000000      /* Freeze countes on
-                                          Enabled Condition or
-                                          Event */
-
-#define PMRN_UPMC0     0x000   /* User Performance Monitor Counter 0 */
-#define PMRN_UPMC1     0x001   /* User Performance Monitor Counter 1 */
-#define PMRN_UPMC2     0x002   /* User Performance Monitor Counter 1 */
-#define PMRN_UPMC3     0x003   /* User Performance Monitor Counter 1 */
-#define PMRN_UPMLCA0   0x080   /* User PM Local Control A0 */
-#define PMRN_UPMLCA1   0x081   /* User PM Local Control A1 */
-#define PMRN_UPMLCA2   0x082   /* User PM Local Control A2 */
-#define PMRN_UPMLCA3   0x083   /* User PM Local Control A3 */
-#define PMRN_UPMLCB0   0x100   /* User PM Local Control B0 */
-#define PMRN_UPMLCB1   0x101   /* User PM Local Control B1 */
-#define PMRN_UPMLCB2   0x102   /* User PM Local Control B2 */
-#define PMRN_UPMLCB3   0x103   /* User PM Local Control B3 */
-#define PMRN_UPMGC0    0x180   /* User PM Global Control 0 */
-
-
 /* Machine State Register (MSR) Fields */
 #define MSR_UCLE       (1<<26) /* User-mode cache lock enable */
 #define MSR_SPE                (1<<25) /* Enable SPE */
diff --git a/include/asm-powerpc/reg_fsl_emb.h b/include/asm-powerpc/reg_fsl_emb.h
new file mode 100644 (file)
index 0000000..1e180a5
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Contains register definitions for the Freescale Embedded Performance
+ * Monitor.
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_POWERPC_REG_FSL_EMB_H__
+#define __ASM_POWERPC_REG_FSL_EMB_H__
+
+#ifndef __ASSEMBLY__
+/* Performance Monitor Registers */
+#define mfpmr(rn)      ({unsigned int rval; \
+                       asm volatile("mfpmr %0," __stringify(rn) \
+                                    : "=r" (rval)); rval;})
+#define mtpmr(rn, v)   asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
+#endif /* __ASSEMBLY__ */
+
+/* Freescale Book E Performance Monitor APU Registers */
+#define PMRN_PMC0      0x010   /* Performance Monitor Counter 0 */
+#define PMRN_PMC1      0x011   /* Performance Monitor Counter 1 */
+#define PMRN_PMC2      0x012   /* Performance Monitor Counter 1 */
+#define PMRN_PMC3      0x013   /* Performance Monitor Counter 1 */
+#define PMRN_PMLCA0    0x090   /* PM Local Control A0 */
+#define PMRN_PMLCA1    0x091   /* PM Local Control A1 */
+#define PMRN_PMLCA2    0x092   /* PM Local Control A2 */
+#define PMRN_PMLCA3    0x093   /* PM Local Control A3 */
+
+#define PMLCA_FC       0x80000000      /* Freeze Counter */
+#define PMLCA_FCS      0x40000000      /* Freeze in Supervisor */
+#define PMLCA_FCU      0x20000000      /* Freeze in User */
+#define PMLCA_FCM1     0x10000000      /* Freeze when PMM==1 */
+#define PMLCA_FCM0     0x08000000      /* Freeze when PMM==0 */
+#define PMLCA_CE       0x04000000      /* Condition Enable */
+
+#define PMLCA_EVENT_MASK 0x007f0000    /* Event field */
+#define PMLCA_EVENT_SHIFT      16
+
+#define PMRN_PMLCB0    0x110   /* PM Local Control B0 */
+#define PMRN_PMLCB1    0x111   /* PM Local Control B1 */
+#define PMRN_PMLCB2    0x112   /* PM Local Control B2 */
+#define PMRN_PMLCB3    0x113   /* PM Local Control B3 */
+
+#define PMLCB_THRESHMUL_MASK   0x0700  /* Threshhold Multiple Field */
+#define PMLCB_THRESHMUL_SHIFT  8
+
+#define PMLCB_THRESHOLD_MASK   0x003f  /* Threshold Field */
+#define PMLCB_THRESHOLD_SHIFT  0
+
+#define PMRN_PMGC0     0x190   /* PM Global Control 0 */
+
+#define PMGC0_FAC      0x80000000      /* Freeze all Counters */
+#define PMGC0_PMIE     0x40000000      /* Interrupt Enable */
+#define PMGC0_FCECE    0x20000000      /* Freeze countes on
+                                          Enabled Condition or
+                                          Event */
+
+#define PMRN_UPMC0     0x000   /* User Performance Monitor Counter 0 */
+#define PMRN_UPMC1     0x001   /* User Performance Monitor Counter 1 */
+#define PMRN_UPMC2     0x002   /* User Performance Monitor Counter 1 */
+#define PMRN_UPMC3     0x003   /* User Performance Monitor Counter 1 */
+#define PMRN_UPMLCA0   0x080   /* User PM Local Control A0 */
+#define PMRN_UPMLCA1   0x081   /* User PM Local Control A1 */
+#define PMRN_UPMLCA2   0x082   /* User PM Local Control A2 */
+#define PMRN_UPMLCA3   0x083   /* User PM Local Control A3 */
+#define PMRN_UPMLCB0   0x100   /* User PM Local Control B0 */
+#define PMRN_UPMLCB1   0x101   /* User PM Local Control B1 */
+#define PMRN_UPMLCB2   0x102   /* User PM Local Control B2 */
+#define PMRN_UPMLCB3   0x103   /* User PM Local Control B3 */
+#define PMRN_UPMGC0    0x180   /* User PM Global Control 0 */
+
+
+#endif /* __ASM_POWERPC_REG_FSL_EMB_H__ */
+#endif /* __KERNEL__ */
index bc9739dff5e75cd9a808c895092b7e98066ceda0..29552ff182aa161204490d48bb26d9ec1e613e2e 100644 (file)
@@ -65,7 +65,7 @@
 struct task_struct;
 struct pt_regs;
 
-#ifdef CONFIG_DEBUGGER
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 
 extern int (*__debugger)(struct pt_regs *regs);
 extern int (*__debugger_ipi)(struct pt_regs *regs);
@@ -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 9204c15839c57a01e6fe31720ead644705a08069..56512a968dab9075666ac15a9437bd3c1a25529c 100644 (file)
@@ -66,7 +66,7 @@ extern void __devinit vio_unregister_device(struct vio_dev *dev);
 
 struct device_node;
 
-extern struct vio_dev * __devinit vio_register_device_node(
+extern struct vio_dev *vio_register_device_node(
                struct device_node *node_vdev);
 extern const void *vio_get_attribute(struct vio_dev *vdev, char *which,
                int *length);
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 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 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 2f8ff3fa095730e2de64051e2fbf2595a47a6fae..d2516eed3a3890efb8bf4edc2172eb1ae3a4312e 100644 (file)
@@ -91,7 +91,6 @@ typedef struct {
        unsigned int    pr_q[64];
 } elf_fpregset_t;
 
-#ifdef __KERNEL__
 #include <asm/mbus.h>
 
 /*
@@ -144,6 +143,4 @@ typedef struct {
 
 #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 217d768cf7dd7c195d9f4050014a4b45a7ad6512..272a65873f2e0c537f4178592afd11a1db664cfa 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
@@ -155,7 +153,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;                        \
@@ -174,6 +171,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 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 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 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 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 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 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 63f2e6ed698f5ba471efab1f7f5af1cc4942fb96..ddbe7efe590e96bdf25e8c1afa96038126f7a329 100644 (file)
@@ -25,6 +25,7 @@
 #ifndef _LINUX_ACPI_H
 #define _LINUX_ACPI_H
 
+#include <linux/ioport.h>      /* for struct resource */
 
 #ifdef CONFIG_ACPI
 
@@ -43,8 +44,6 @@
 #include <linux/dmi.h>
 
 
-#ifdef CONFIG_ACPI
-
 enum acpi_irq_model_id {
        ACPI_IRQ_MODEL_PIC = 0,
        ACPI_IRQ_MODEL_IOAPIC,
@@ -80,7 +79,6 @@ typedef int (*acpi_table_handler) (struct acpi_table_header *table);
 typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
 
 char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
-unsigned long acpi_find_rsdp (void);
 int acpi_boot_init (void);
 int acpi_boot_table_init (void);
 int acpi_numa_init (void);
@@ -115,8 +113,8 @@ int acpi_unmap_lsapic(int cpu);
 
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
 int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
-
-extern int acpi_mp_config;
+void acpi_irq_stats_init(void);
+extern u32 acpi_irq_handled;
 
 extern struct acpi_mcfg_allocation *pci_mmcfg_config;
 extern int pci_mmcfg_config_num;
@@ -124,12 +122,6 @@ extern int pci_mmcfg_config_num;
 extern int sbf_port;
 extern unsigned long acpi_realmode_flags;
 
-#else  /* !CONFIG_ACPI */
-
-#define acpi_mp_config 0
-
-#endif         /* !CONFIG_ACPI */
-
 int acpi_register_gsi (u32 gsi, int triggering, int polarity);
 int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
@@ -145,8 +137,6 @@ extern int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity);
  */
 void acpi_unregister_gsi (u32 gsi);
 
-#ifdef CONFIG_ACPI
-
 struct acpi_prt_entry {
        struct list_head        node;
        struct acpi_pci_id      id;
@@ -179,8 +169,6 @@ struct acpi_pci_driver {
 int acpi_pci_register_driver(struct acpi_pci_driver *driver);
 void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
 
-#endif /* CONFIG_ACPI */
-
 #ifdef CONFIG_ACPI_EC
 
 extern int ec_read(u8 addr, u8 *val);
@@ -192,6 +180,26 @@ extern int ec_transaction(u8 command,
 
 #endif /*CONFIG_ACPI_EC*/
 
+#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
+
+typedef void (*wmi_notify_handler) (u32 value, void *context);
+
+extern acpi_status wmi_evaluate_method(const char *guid, u8 instance,
+                                       u32 method_id,
+                                       const struct acpi_buffer *in,
+                                       struct acpi_buffer *out);
+extern acpi_status wmi_query_block(const char *guid, u8 instance,
+                                       struct acpi_buffer *out);
+extern acpi_status wmi_set_block(const char *guid, u8 instance,
+                                       const struct acpi_buffer *in);
+extern acpi_status wmi_install_notify_handler(const char *guid,
+                                       wmi_notify_handler handler, void *data);
+extern acpi_status wmi_remove_notify_handler(const char *guid);
+extern acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out);
+extern bool wmi_has_guid(const char *guid);
+
+#endif /* CONFIG_ACPI_WMI */
+
 extern int acpi_blacklisted(void);
 #ifdef CONFIG_DMI
 extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
@@ -217,6 +225,13 @@ extern int pnpacpi_disabled;
 #define PXM_INVAL      (-1)
 #define NID_INVAL      (-1)
 
+int acpi_check_resource_conflict(struct resource *res);
+
+int acpi_check_region(resource_size_t start, resource_size_t n,
+                     const char *name);
+int acpi_check_mem_region(resource_size_t start, resource_size_t n,
+                     const char *name);
+
 #else  /* CONFIG_ACPI */
 
 static inline int acpi_boot_init(void)
@@ -229,5 +244,22 @@ static inline int acpi_boot_table_init(void)
        return 0;
 }
 
+static inline int acpi_check_resource_conflict(struct resource *res)
+{
+       return 0;
+}
+
+static inline int acpi_check_region(resource_size_t start, resource_size_t n,
+                                   const char *name)
+{
+       return 0;
+}
+
+static inline int acpi_check_mem_region(resource_size_t start,
+                                       resource_size_t n, const char *name)
+{
+       return 0;
+}
+
 #endif /* !CONFIG_ACPI */
 #endif /*_LINUX_ACPI_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 23932d7741a996721162dc264290adbed5248f6a..ddd8652fc3f38a91d5f471fd70a534e21337ba12 100644 (file)
@@ -167,6 +167,10 @@ struct cpufreq_governor {
        char    name[CPUFREQ_NAME_LEN];
        int     (*governor)     (struct cpufreq_policy *policy,
                                 unsigned int event);
+       ssize_t (*show_setspeed)        (struct cpufreq_policy *policy,
+                                        char *buf);
+       int     (*store_setspeed)       (struct cpufreq_policy *policy,
+                                        unsigned int freq);
        unsigned int max_transition_latency; /* HW must be able to switch to
                        next freq faster than this value in nano secs or we
                        will fallback to performance governor */
index b0fd85ab9efb07efc8c39ef6e3857e29caa93dfb..385d45b616db2059e9aa71441b8e918ac11cac28 100644 (file)
@@ -46,9 +46,10 @@ struct cpuidle_state {
 /* Idle State Flags */
 #define CPUIDLE_FLAG_TIME_VALID        (0x01) /* is residency time measurable? */
 #define CPUIDLE_FLAG_CHECK_BM  (0x02) /* BM activity will exit state */
-#define CPUIDLE_FLAG_SHALLOW   (0x10) /* low latency, minimal savings */
-#define CPUIDLE_FLAG_BALANCED  (0x20) /* medium latency, moderate savings */
-#define CPUIDLE_FLAG_DEEP      (0x40) /* high latency, large savings */
+#define CPUIDLE_FLAG_POLL      (0x10) /* no latency, no savings */
+#define CPUIDLE_FLAG_SHALLOW   (0x20) /* low latency, minimal savings */
+#define CPUIDLE_FLAG_BALANCED  (0x40) /* medium latency, moderate savings */
+#define CPUIDLE_FLAG_DEEP      (0x80) /* high latency, large savings */
 
 #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
 
@@ -178,4 +179,10 @@ static inline void cpuidle_unregister_governor(struct cpuidle_governor *gov) { }
 
 #endif
 
+#ifdef CONFIG_ARCH_HAS_CPU_RELAX
+#define CPUIDLE_DRIVER_STATE_START     1
+#else
+#define CPUIDLE_DRIVER_STATE_START     0
+#endif
+
 #endif /* _LINUX_CPUIDLE_H */
index 5b42a659a308d046a886ca86fd05e260822a77b4..b1251b2af568b6d2c7c3063b7d4f57a071c79c1e 100644 (file)
@@ -79,7 +79,6 @@ extern void dmi_scan_machine(void);
 extern int dmi_get_year(int field);
 extern int dmi_name_in_vendors(const char *str);
 extern int dmi_available;
-extern char *dmi_get_slot(int slot);
 
 #else
 
@@ -90,7 +89,6 @@ static inline const struct dmi_device * dmi_find_device(int type, const char *na
 static inline int dmi_get_year(int year) { return 0; }
 static inline int dmi_name_in_vendors(const char *s) { return 0; }
 #define dmi_available 0
-static inline char *dmi_get_slot(int slot) { return NULL; }
 
 #endif
 
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 7ceb24d87c1a970b06835f5c645bb0ab2e31f1d0..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;
 
@@ -355,6 +357,7 @@ typedef struct elf64_shdr {
 #define NT_AUXV                6
 #define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
 #define NT_PPC_VMX     0x100           /* PowerPC Altivec/VMX registers */
+#define NT_PPC_SPE     0x101           /* PowerPC SPE/EVR registers */
 #define NT_386_TLS     0x200           /* i386 TLS slots (struct user_desc) */
 
 
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 109734bf6377cb3e8392a51ae597df12025cb8be..36b7abefacbe4b743ba128afcdcfee7b5c05a885 100644 (file)
@@ -1241,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 *);
@@ -1767,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 *);
@@ -1941,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);
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 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 18222f267bc4043f0a0ff0be1201d58938f1063a..9e01f376840a8c154327badfdd3a94f1f3643713 100644 (file)
@@ -243,6 +243,7 @@ extern enum system_states {
 #define TAINT_BAD_PAGE                 (1<<5)
 #define TAINT_USER                     (1<<6)
 #define TAINT_DIE                      (1<<7)
+#define TAINT_OVERRIDDEN_ACPI_TABLE    (1<<8)
 
 extern void dump_stack(void) __cold;
 
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 00f89fd6c52a21f83d26a7b94e351e3c782854bf..0201f6f51ceab72892ce6b2c167d8dceaa2a23d5 100644 (file)
@@ -38,6 +38,11 @@ struct led_classdev {
        void            (*brightness_set)(struct led_classdev *led_cdev,
                                          enum led_brightness brightness);
 
+       /* Activate hardware accelerated blink */
+       int             (*blink_set)(struct led_classdev *led_cdev,
+                                    unsigned long *delay_on,
+                                    unsigned long *delay_off);
+
        struct device           *dev;
        struct list_head         node;                  /* LED Device list */
        char                    *default_trigger;       /* Trigger to use */
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 */
index e17c5343cf517e6938c93551e6878400b6a11046..b0ddf4b25862392d90443a8ad88a9d6c7ad68b95 100644 (file)
@@ -98,6 +98,18 @@ static inline int cfi_interleave_supported(int i)
 #define CFI_DEVICETYPE_X32 (32 / 8)
 #define CFI_DEVICETYPE_X64 (64 / 8)
 
+
+/* Device Interface Code Assignments from the "Common Flash Memory Interface
+ * Publication 100" dated December 1, 2001.
+ */
+#define CFI_INTERFACE_X8_ASYNC         0x0000
+#define CFI_INTERFACE_X16_ASYNC                0x0001
+#define CFI_INTERFACE_X8_BY_X16_ASYNC  0x0002
+#define CFI_INTERFACE_X32_ASYNC                0x0003
+#define CFI_INTERFACE_X16_BY_X32_ASYNC 0x0005
+#define CFI_INTERFACE_NOT_ALLOWED      0xffff
+
+
 /* NB: We keep these structures in memory in HOST byteorder, except
  * where individually noted.
  */
index 783fc983417c9786c8d99eecca5dd19a36e4895d..0a13bb35f044fa249c58f54e0ceab9bbe9e01f23 100644 (file)
@@ -152,6 +152,15 @@ struct mtd_info {
        int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
        int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
+       /* In blackbox flight recorder like scenarios we want to make successful
+          writes in interrupt context. panic_write() is only intended to be
+          called when its known the kernel is about to panic and we need the
+          write to succeed. Since the kernel is not going to be running for much
+          longer, this function can break locks and delay to ensure the write
+          succeeds (but not sleep). */
+
+       int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+
        int (*read_oob) (struct mtd_info *mtd, loff_t from,
                         struct mtd_oob_ops *ops);
        int (*write_oob) (struct mtd_info *mtd, loff_t to,
diff --git a/include/linux/mtd/mtdram.h b/include/linux/mtd/mtdram.h
new file mode 100644 (file)
index 0000000..04fdc07
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __MTD_MTDRAM_H__
+#define __MTD_MTDRAM_H__
+
+#include <linux/mtd/mtd.h>
+int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
+                       unsigned long size, char *name);
+
+#endif /* __MTD_MTDRAM_H__ */
index c46161f4eee3836165e5733e41021605bd6f1357..d1b310c92eb45a9272c8ba2ac30c26becb856a5e 100644 (file)
@@ -67,6 +67,7 @@
 /*
  * Device ID Register F001h (R)
  */
+#define ONENAND_DEVICE_DENSITY_MASK    (0xf)
 #define ONENAND_DEVICE_DENSITY_SHIFT   (4)
 #define ONENAND_DEVICE_IS_DDP          (1 << 3)
 #define ONENAND_DEVICE_IS_DEMUX                (1 << 2)
index da6b3d6f12a7642442642032f58b4e917ee6b3e4..7c37d7e55abcbc119f3496c08e92868343dcd782 100644 (file)
@@ -71,5 +71,12 @@ extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
 
 #define put_partition_parser(p) do { module_put((p)->owner); } while(0)
 
-#endif
+struct device;
+struct device_node;
+
+int __devinit of_mtd_parse_partitions(struct device *dev,
+                                      struct mtd_info *mtd,
+                                      struct device_node *node,
+                                      struct mtd_partition **pparts);
 
+#endif
index 3d967b6b120a3eb8ba5fb2d5150c0d508df9c191..f71201d0f3e7e42f2ffe22d571231cc958dff04f 100644 (file)
 #include <linux/types.h>
 #include <mtd/ubi-user.h>
 
-/*
- * UBI data type hint constants.
- *
- * UBI_LONGTERM: long-term data
- * UBI_SHORTTERM: short-term data
- * UBI_UNKNOWN: data persistence is unknown
- *
- * These constants are used when data is written to UBI volumes in order to
- * help the UBI wear-leveling unit to find more appropriate physical
- * eraseblocks.
- */
-enum {
-       UBI_LONGTERM = 1,
-       UBI_SHORTTERM,
-       UBI_UNKNOWN
-};
-
 /*
  * enum ubi_open_mode - UBI volume open mode constants.
  *
@@ -167,6 +150,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
                   int len, int dtype);
 int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum);
 int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum);
+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
 int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum);
 
 /*
index b5f33efcb8e20006165336ffbcdd9e25c7e793b3..6981016dcc258fc89a0956ca6d9cb41ef3f771ba 100644 (file)
@@ -50,6 +50,7 @@ extern struct device_node *of_find_matching_node(struct device_node *from,
 extern struct device_node *of_find_node_by_path(const char *path);
 extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_parent(struct device_node *node);
 extern struct device_node *of_get_next_child(const struct device_node *node,
                                             struct device_node *prev);
 #define for_each_child_of_node(parent, child) \
index 5cbf3e371012a8ed26b361d72a1614d4d9a0c03b..68ed19ccf1f702c1978c8fb5e18ed557f316484c 100644 (file)
@@ -94,6 +94,7 @@ enum power_supply_property {
        /* Properties of type `const char *' */
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
+       POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 
 enum power_supply_type {
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);
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 7c8ca05c3cae4368a85da8a56b58050d5bd74944..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;
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 40c7b5d993b932f83864f04255e1853acd099dc5..f41ffd7c2dd9f611d0cc7e15d4f245f63b461116 100644 (file)
 #define SONYPI_EVENT_FNKEY_RELEASED            59
 #define SONYPI_EVENT_WIRELESS_ON               60
 #define SONYPI_EVENT_WIRELESS_OFF              61
+#define SONYPI_EVENT_ZOOM_IN_PRESSED           62
+#define SONYPI_EVENT_ZOOM_OUT_PRESSED          63
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT         _IOR('v', 0, __u8)
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);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
new file mode 100644 (file)
index 0000000..bba7712
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  thermal.h  ($Revision: 0 $)
+ *
+ *  Copyright (C) 2008  Intel Corp
+ *  Copyright (C) 2008  Zhang Rui <rui.zhang@intel.com>
+ *  Copyright (C) 2008  Sujith Thomas <sujith.thomas@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef __THERMAL_H__
+#define __THERMAL_H__
+
+#include <linux/idr.h>
+#include <linux/device.h>
+
+struct thermal_zone_device;
+struct thermal_cooling_device;
+
+struct thermal_zone_device_ops {
+       int (*bind) (struct thermal_zone_device *,
+                    struct thermal_cooling_device *);
+       int (*unbind) (struct thermal_zone_device *,
+                      struct thermal_cooling_device *);
+       int (*get_temp) (struct thermal_zone_device *, char *);
+       int (*get_mode) (struct thermal_zone_device *, char *);
+       int (*set_mode) (struct thermal_zone_device *, const char *);
+       int (*get_trip_type) (struct thermal_zone_device *, int, char *);
+       int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
+};
+
+struct thermal_cooling_device_ops {
+       int (*get_max_state) (struct thermal_cooling_device *, char *);
+       int (*get_cur_state) (struct thermal_cooling_device *, char *);
+       int (*set_cur_state) (struct thermal_cooling_device *, unsigned int);
+};
+
+#define THERMAL_TRIPS_NONE -1
+#define THERMAL_MAX_TRIPS 10
+#define THERMAL_NAME_LENGTH 20
+struct thermal_cooling_device {
+       int id;
+       char type[THERMAL_NAME_LENGTH];
+       struct device device;
+       void *devdata;
+       struct thermal_cooling_device_ops *ops;
+       struct list_head node;
+};
+
+#define KELVIN_TO_CELSIUS(t)   (long)(((long)t-2732 >= 0) ?    \
+                               ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
+#define CELSIUS_TO_KELVIN(t)   ((t)*10+2732)
+
+struct thermal_zone_device {
+       int id;
+       char type[THERMAL_NAME_LENGTH];
+       struct device device;
+       void *devdata;
+       int trips;
+       struct thermal_zone_device_ops *ops;
+       struct list_head cooling_devices;
+       struct idr idr;
+       struct mutex lock;      /* protect cooling devices list */
+       struct list_head node;
+};
+
+struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
+                                       struct thermal_zone_device_ops *);
+void thermal_zone_device_unregister(struct thermal_zone_device *);
+
+int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
+                                    struct thermal_cooling_device *);
+int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
+                                      struct thermal_cooling_device *);
+
+struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
+                                       struct thermal_cooling_device_ops *);
+void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+
+#endif                         /* __THERMAL_H__ */
index 5824a9777ad7d39cc13a67910936cafbb2cce178..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;
index f71dac4203948421595e0f79cad9140c70d7c903..615072c4da04415e8f14e02372078abb3d987941 100644 (file)
@@ -29,7 +29,7 @@ struct mtd_oob_buf {
 #define MTD_WRITEABLE          0x400   /* Device is writeable */
 #define MTD_BIT_WRITEABLE      0x800   /* Single bits can be flipped */
 #define MTD_NO_ERASE           0x1000  /* No erase necessary */
-#define MTD_STUPID_LOCK                0x2000  /* Always locked after reset */
+#define MTD_POWERUP_LOCK       0x2000  /* Always locked after reset */
 
 // Some common devices / combinations of capabilities
 #define MTD_CAP_ROM            0
index 74efa77634790f6ab0ad4c1395f543f13211c304..292f916ea5642178947204ba04a1d0f2d5b26c64 100644 (file)
@@ -57,6 +57,43 @@ enum {
        UBI_VID_STATIC  = 2
 };
 
+/*
+ * Volume flags used in the volume table record.
+ *
+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
+ *
+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
+ * table. UBI automatically re-sizes the volume which has this flag and makes
+ * the volume to be of largest possible size. This means that if after the
+ * initialization UBI finds out that there are available physical eraseblocks
+ * present on the device, it automatically appends all of them to the volume
+ * (the physical eraseblocks reserved for bad eraseblocks handling and other
+ * reserved physical eraseblocks are not taken). So, if there is a volume with
+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
+ * eraseblocks will be zero after UBI is loaded, because all of them will be
+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
+ * after the volume had been initialized.
+ *
+ * The auto-resize feature is useful for device production purposes. For
+ * example, different NAND flash chips may have different amount of initial bad
+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND
+ * chips usually guarantee that the amount of initial bad eraseblocks does not
+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be
+ * flashed to the end devices in production, he does not know the exact amount
+ * of good physical eraseblocks the NAND chip on the device will have, but this
+ * number is required to calculate the volume sized and put them to the volume
+ * table of the UBI image. In this case, one of the volumes (e.g., the one
+ * which will store the root file system) is marked as "auto-resizable", and
+ * UBI will adjust its size on the first boot if needed.
+ *
+ * Note, first UBI reserves some amount of physical eraseblocks for bad
+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This
+ * means that the pool of reserved physical eraseblocks will always be present.
+ */
+enum {
+       UBI_VTBL_AUTORESIZE_FLG = 0x01,
+};
+
 /*
  * Compatibility constants used by internal volumes.
  *
@@ -262,7 +299,9 @@ struct ubi_vid_hdr {
 
 /* The layout volume contains the volume table */
 
-#define UBI_LAYOUT_VOL_ID        UBI_INTERNAL_VOL_START
+#define UBI_LAYOUT_VOLUME_ID     UBI_INTERNAL_VOL_START
+#define UBI_LAYOUT_VOLUME_TYPE   UBI_VID_DYNAMIC
+#define UBI_LAYOUT_VOLUME_ALIGN  1
 #define UBI_LAYOUT_VOLUME_EBS    2
 #define UBI_LAYOUT_VOLUME_NAME   "layout volume"
 #define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
@@ -289,7 +328,8 @@ struct ubi_vid_hdr {
  * @upd_marker: if volume update was started but not finished
  * @name_len: volume name length
  * @name: the volume name
- * @padding2: reserved, zeroes
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ * @padding: reserved, zeroes
  * @crc: a CRC32 checksum of the record
  *
  * The volume table records are stored in the volume table, which is stored in
@@ -324,7 +364,8 @@ struct ubi_vtbl_record {
        __u8    upd_marker;
        __be16  name_len;
        __u8    name[UBI_VOL_NAME_MAX+1];
-       __u8    padding2[24];
+       __u8    flags;
+       __u8    padding[23];
        __be32  crc;
 } __attribute__ ((packed));
 
index fe06ded0e6b860ac1f7447f78446cca2b797c860..a7421f130cc019a3e4144090a3848bf338f3be4b 100644 (file)
 #define __UBI_USER_H__
 
 /*
+ * UBI device creation (the same as MTD device attachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI
+ * control device. The caller has to properly fill and pass
+ * &struct ubi_attach_req object - UBI will attach the MTD device specified in
+ * the request and return the newly created UBI device number as the ioctl
+ * return value.
+ *
+ * UBI device deletion (the same as MTD device detachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI
+ * control device.
+ *
  * UBI volume creation
  * ~~~~~~~~~~~~~~~~~~~
  *
@@ -48,7 +63,7 @@
  *
  * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the
  * corresponding UBI volume character device. A pointer to a 64-bit update
- * size should be passed to the IOCTL. After then, UBI expects user to write
+ * size should be passed to the IOCTL. After this, UBI expects user to write
  * this number of bytes to the volume character device. The update is finished
  * when the claimed number of bytes is passed. So, the volume update sequence
  * is something like:
  * ioctl(fd, UBI_IOCVOLUP, &image_size);
  * write(fd, buf, image_size);
  * close(fd);
+ *
+ * Atomic eraseblock change
+ * ~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL
+ * command of the corresponding UBI volume character device. A pointer to
+ * &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is
+ * expected to write the requested amount of bytes. This is similar to the
+ * "volume update" IOCTL.
  */
 
 /*
- * When a new volume is created, users may either specify the volume number they
- * want to create or to let UBI automatically assign a volume number using this
- * constant.
+ * When a new UBI volume or UBI device is created, users may either specify the
+ * volume/device number they want to create or to let UBI automatically assign
+ * the number using these constants.
  */
 #define UBI_VOL_NUM_AUTO (-1)
+#define UBI_DEV_NUM_AUTO (-1)
 
 /* Maximum volume name length */
 #define UBI_MAX_VOLUME_NAME 127
 /* Re-size an UBI volume */
 #define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
 
+/* IOCTL commands of the UBI control character device */
+
+#define UBI_CTRL_IOC_MAGIC 'o'
+
+/* Attach an MTD device */
+#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req)
+/* Detach an MTD device */
+#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t)
+
 /* IOCTL commands of UBI volume character devices */
 
 #define UBI_VOL_IOC_MAGIC 'O'
 #define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
 /* An eraseblock erasure command, used for debugging, disabled by default */
 #define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
+/* An atomic eraseblock change command */
+#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
+
+/* Maximum MTD device name length supported by UBI */
+#define MAX_UBI_MTD_NAME_LEN 127
+
+/*
+ * UBI data type hint constants.
+ *
+ * UBI_LONGTERM: long-term data
+ * UBI_SHORTTERM: short-term data
+ * UBI_UNKNOWN: data persistence is unknown
+ *
+ * These constants are used when data is written to UBI volumes in order to
+ * help the UBI wear-leveling unit to find more appropriate physical
+ * eraseblocks.
+ */
+enum {
+       UBI_LONGTERM  = 1,
+       UBI_SHORTTERM = 2,
+       UBI_UNKNOWN   = 3,
+};
 
 /*
  * UBI volume type constants.
  */
 enum {
        UBI_DYNAMIC_VOLUME = 3,
-       UBI_STATIC_VOLUME = 4
+       UBI_STATIC_VOLUME  = 4,
+};
+
+/**
+ * struct ubi_attach_req - attach MTD device request.
+ * @ubi_num: UBI device number to create
+ * @mtd_num: MTD device number to attach
+ * @vid_hdr_offset: VID header offset (use defaults if %0)
+ * @padding: reserved for future, not used, has to be zeroed
+ *
+ * This data structure is used to specify MTD device UBI has to attach and the
+ * parameters it has to use. The number which should be assigned to the new UBI
+ * device is passed in @ubi_num. UBI may automatically assign the number if
+ * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in
+ * @ubi_num.
+ *
+ * Most applications should pass %0 in @vid_hdr_offset to make UBI use default
+ * offset of the VID header within physical eraseblocks. The default offset is
+ * the next min. I/O unit after the EC header. For example, it will be offset
+ * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or
+ * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages.
+ *
+ * But in rare cases, if this optimizes things, the VID header may be placed to
+ * a different offset. For example, the boot-loader might do things faster if the
+ * VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As
+ * the boot-loader would not normally need to read EC headers (unless it needs
+ * UBI in RW mode), it might be faster to calculate ECC. This is weird example,
+ * but it real-life example. So, in this example, @vid_hdr_offer would be
+ * 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes
+ * aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page
+ * of the first page and add needed padding.
+ */
+struct ubi_attach_req {
+       int32_t ubi_num;
+       int32_t mtd_num;
+       int32_t vid_hdr_offset;
+       uint8_t padding[12];
 };
 
 /**
  * struct ubi_mkvol_req - volume description data structure used in
- * volume creation requests.
+ *                        volume creation requests.
  * @vol_id: volume number
  * @alignment: volume alignment
  * @bytes: volume size in bytes
  * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
- * @padding1: reserved for future, not used
+ * @padding1: reserved for future, not used, has to be zeroed
  * @name_len: volume name length
- * @padding2: reserved for future, not used
+ * @padding2: reserved for future, not used, has to be zeroed
  * @name: volume name
  *
- * This structure is used by userspace programs when creating new volumes. The
+ * This structure is used by user-space programs when creating new volumes. The
  * @used_bytes field is only necessary when creating static volumes.
  *
  * The @alignment field specifies the required alignment of the volume logical
@@ -139,7 +231,7 @@ struct ubi_mkvol_req {
        int8_t padding1;
        int16_t name_len;
        int8_t padding2[4];
-       char name[UBI_MAX_VOLUME_NAME+1];
+       char name[UBI_MAX_VOLUME_NAME + 1];
 } __attribute__ ((packed));
 
 /**
@@ -158,4 +250,19 @@ struct ubi_rsvol_req {
        int32_t vol_id;
 } __attribute__ ((packed));
 
+/**
+ * struct ubi_leb_change_req - a data structure used in atomic logical
+ *                             eraseblock change requests.
+ * @lnum: logical eraseblock number to change
+ * @bytes: how many bytes will be written to the logical eraseblock
+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
+ * @padding: reserved for future, not used, has to be zeroed
+ */
+struct ubi_leb_change_req {
+       int32_t lnum;
+       int32_t bytes;
+       uint8_t dtype;
+       uint8_t padding[7];
+} __attribute__ ((packed));
+
 #endif /* __UBI_USER_H__ */
index 92b23e256614ccdb11b94523043551d45fb15036..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
index d53fee8d8604a5514889bfcd93acee4dd882fae0..c0b1e0533d80d32080c8d44acf2ab9f9d90bcbb7 100644 (file)
@@ -538,7 +538,7 @@ skip:
        initrd_end = 0;
 }
 
-static int __init populate_rootfs(void)
+int __init populate_rootfs(void)
 {
        char *err = unpack_to_rootfs(__initramfs_start,
                         __initramfs_end - __initramfs_start, 0);
@@ -577,4 +577,10 @@ static int __init populate_rootfs(void)
        }
        return 0;
 }
+#ifndef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+/*
+ * if this option is enabled, populate_rootfs() is called _earlier_ in the
+ * boot sequence. This insures that the ACPI initialisation can find the file.
+ */
 rootfs_initcall(populate_rootfs);
+#endif
index c691f5f7fc27b40ea6b2df39e2fef9ac52b4cd0a..2a78932f6c075abd36b331db09191b785d3156bc 100644 (file)
@@ -102,6 +102,12 @@ static inline void mark_rodata_ro(void) { }
 extern void tc_init(void);
 #endif
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
+extern int populate_rootfs(void);
+#else
+static inline void populate_rootfs(void) {}
+#endif
+
 enum system_states system_state;
 EXPORT_SYMBOL(system_state);
 
@@ -648,6 +654,7 @@ asmlinkage void __init start_kernel(void)
 
        check_bugs();
 
+       populate_rootfs(); /* For DSDT override from initramfs */
        acpi_early_init(); /* before LAPIC and SMP init */
 
        /* Do the rest non-__init'ed, we're now alive */
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 3995297567a9f0a28467f71475e84880199f79ce..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))
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 d9e90cfe3298ca09947aca7b562479c5fcacb6f8..24af9f8bac99204076ab80b36038d1d5404ae27a 100644 (file)
@@ -161,7 +161,7 @@ const char *print_tainted(void)
 {
        static char buf[20];
        if (tainted) {
-               snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c",
+               snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c",
                        tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G',
                        tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
                        tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
@@ -169,7 +169,8 @@ const char *print_tainted(void)
                        tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
                        tainted & TAINT_BAD_PAGE ? 'B' : ' ',
                        tainted & TAINT_USER ? 'U' : ' ',
-                       tainted & TAINT_DIE ? 'D' : ' ');
+                       tainted & TAINT_DIE ? 'D' : ' ',
+                       tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ');
        }
        else
                snprintf(buf, sizeof(buf), "Not tainted");
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 ef9b802738a522851d7e95672164f83a997d8df6..79833170bb9cddf4aad9b6bde7806628856ffde5 100644 (file)
@@ -74,8 +74,8 @@ config PM_TRACE_RTC
        RTC across reboots, so that you can debug a machine that just hangs
        during suspend (or more commonly, during resume).
 
-       To use this debugging feature you should attempt to suspend the machine,
-       then reboot it, then run
+       To use this debugging feature you should attempt to suspend the
+       machine, reboot it and then run
 
                dmesg -s 1000000 | grep 'hash matches'
 
@@ -123,7 +123,10 @@ config HIBERNATION
          called "hibernation" in user interfaces.  STD checkpoints the
          system and powers it off; and restores that checkpoint on reboot.
 
-         You can suspend your machine with 'echo disk > /sys/power/state'.
+         You can suspend your machine with 'echo disk > /sys/power/state'
+         after placing resume=/dev/swappartition on the kernel command line
+         in your bootloader's configuration file.
+
          Alternatively, you can use the additional userland tools available
          from <http://suspend.sf.net>.
 
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 86daaa26d1200c359f8f7c150e1ad5d7ddc1f70d..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",
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 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 9d073fa0a2d02631f53ba3117e80b32efc2b9ae9..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>
@@ -1144,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;
@@ -1165,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;
 }
@@ -1641,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
         */
@@ -1672,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)
@@ -1696,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);
@@ -2036,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);
@@ -2073,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;
        }
 
@@ -2085,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);
@@ -2114,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);
 
@@ -2131,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;
 }
@@ -2246,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);
 
        /*
@@ -2281,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 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 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 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 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;
        }